Latest bug-fixes with added tests.
// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// This file contains the implementation of the Simulator TSY call classes. The call classes
// process the call-based requests made by ETel clients and passed down to the TSY by the
// ETel Server.
//
//
/**
@file
*/
#include "CSimCall.h"
#include "CSimPhone.h"
#include "Simlog.h"
void CSimCall::CloseCall(TAny* aObj)
/**
* Utility func for cleanup stack
*
* @param aObj a pointer to the CObject to close
*/
{
((CObject*)aObj)->Close();
}
CSimCall::CSimCall(CSimLine* aLine,const TName& aName, CSimPhone* aPhone)
: iState(RMobileCall::EStatusIdle),iLine(aLine),
iHookState(ConvertStateToHook(iState)), iPhone(aPhone)
{
iNotifyStatusChange.iNotifyPending = EFalse;
iMobileNotifyStatusChange.iNotifyPending = EFalse;
iAnswerIncomingCall.iNotifyPending = EFalse;
iName.Copy(aName);
}
void CSimCall::ConstructL()
/**
* Standard constructor
*/
{
iCallDurationHandler = CSimCallDuration::NewL(this);
iNotifyRemotePartyInfoTimer = CSimCallRemotePartyInfoChange::NewL(this);
}
CSimCall::~CSimCall()
/**
* Standard destructor
*/
{
iLine->CallDestructor(this);
delete iCallDurationHandler;
delete iNotifyRemotePartyInfoTimer;
}
CTelObject::TReqMode CSimCall::ReqModeL(const TInt aIpc)
/**
* This function returns the Request Mode for the request with the passed IPC value.
* The ETel Server provides a function for returning the standard request modes for
* the Core API requests.
* Multimode API requests mode are handled here.
*
* @param aIpc the IPc number representing the client request
* @return CTelObject::TReqMode the request mode to be used for this IPc number
* @leave Leaves if the IPc number is not found
*/
{
// ReqModeL is called from the server's CTelObject::ReqAnalyserL
// in order to check the type of request it has
CTelObject::TReqMode reqMode=0;
LOGCALL2("CSimCall::ReqModeL called with IPC number %d",aIpc);
switch (aIpc)
{
//
// No Flow Control NOR Multiple Completion
//
case EMobileCallGetMobileDataCallCaps:
case EMobileCallGetMobileCallCaps:
case EMobileCallGetMobileCallStatus:
case EMobileCallGetMobileCallInfo:
case EMobileCallDialEmergencyCall:
case EMobileCallGetMobileDataCallRLPRange:
case EMobileCallSetDynamicHscsdParams:
case EMobileCallGetCurrentHscsdInfo:
case EMobileCallHold:
case EMobileCallResume:
case EMobileCallSwap:
case EMobileCallAnswerISV:
break;
//
// Flow Control Obeyed
//
case EMobileCallDialISV:
reqMode=KReqModeFlowControlObeyed;
break;
//
// Multiple Completion Services with Immediate Server Repost
// (Usually Notifications)
//
case EMobileCallNotifyHscsdInfoChange:
case EMobileCallNotifyMobileCallStatusChange:
case EMobileCallNotifyMobileCallCapsChange:
case EMobileCallNotifyRemotePartyInfoChange:
reqMode=KReqModeMultipleCompletionEnabled | KReqModeRePostImmediately;
break;
default:
reqMode=CCallBase::ReqModeL(aIpc);
break;
}
return reqMode;
}
TInt CSimCall::NumberOfSlotsL(const TInt aIpc)
/**
* NumberOfSlotsL is called by the server when it is registering a new notification
* It enables the TSY to tell the server how many buffer slots to allocate for
* "repost immediately" notifications that may trigger before clients collect them
*
* @param aIpc the IPc number representing the client request
* @return TInt the number of slots required
* @leave Leaves if the IPc number is not found
*/
{
switch (aIpc)
{
case EMobileCallNotifyHscsdInfoChange:
case EMobileCallNotifyMobileDataCallCapsChange:
case EMobileCallNotifyMobileCallStatusChange:
case EMobileCallNotifyMobileCallCapsChange:
case EMobileCallNotifyRemotePartyInfoChange:
LOGCALL1("CSimCall: Registered with default number of slots");
return KDefaultNumberOfSlots;
default:
LOGCALL1("CSimCall::NumberOfSlotsL: No match for IPC, defering to base function");
break;
}
return CCallBase::NumberOfSlotsL(aIpc);
}
TInt CSimCall::RegisterNotification(const TInt /*aIpc*/)
/**
* The ETel Server calls this function when the first client makes a notification
* request. If supported by the underlying protocol controlling the
* signalling stack, this can be used to start requesting updates for the relevant service.
*/
{
return KErrNone;
}
TInt CSimCall::DeregisterNotification(const TInt /*aIpc*/)
/**
* The ETel Server calls this function when the last client that had previously
* made a notification request closes its ETel Server handle. If supported by
* the underlying protocol controlling the signalling stack, this can be used
* to stop requesting updates for the relevant service.
*/
{
return KErrNone;
}
void CSimCall::Init()
/**
* This function can be used to perform any necessary synchronous initialisation.
*/
{}
TInt CSimCall::GetCaps(const TTsyReqHandle aTsyReqHandle,RCall::TCaps* aCallCaps)
/**
* Retrieve the Call capabilities
*
* @param aTsyReqHandle TSY handle associated with this request.s
* @param aCallCaps Pointer to the call capability
* @return KErrNone
*/
{
aCallCaps->iFlags=iCaps;
ReqCompleted(aTsyReqHandle,KErrNone);
return KErrNone;
}
TInt CSimCall::NotifyCapsChange(const TTsyReqHandle aTsyReqHandle, RCall::TCaps* aCaps)
/**
* Register a client's interest in being notified when the call caps change.
* @param aTsyReqHandle The TSY handle associated with this request.
* @param aCaps The capability structure that will be populated with the new capability
* information.
* @return TInt Standard error code.
*/
{
__ASSERT_ALWAYS(!iNotifyCapsChange.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));
iNotifyCapsChange.iNotifyPending=ETrue;
iNotifyCapsChange.iNotifyHandle=aTsyReqHandle;
iNotifyCapsChange.iNotifyData=aCaps;
return KErrNone;
}
TInt CSimCall::NotifyCapsChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancel a client's interest in being notified when the call capabilities change.
*/
{
if(iNotifyCapsChange.iNotifyPending)
{
iNotifyCapsChange.iNotifyPending=EFalse;
ReqCompleted(iNotifyCapsChange.iNotifyHandle,KErrCancel);
}
return KErrNone;
}
TInt CSimCall::GetMobileCallCaps(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps)
/**
* Retrieve the Mobile Call capabilities
*
* @param aTsyReqHandle TSY handle associated with this request.
* @param aCaps Pointer to the call capability
* @return KErrNone
*/
{
TPckg<RMobileCall::TMobileCallCapsV1>* capsPckg=(TPckg<RMobileCall::TMobileCallCapsV1>*)aCaps;
RMobileCall::TMobileCallCapsV1& caps=(*capsPckg)();
// Check that the data structure is supported by the simulated TSY version
TInt err = iPhone->CheckSimTsyVersion(caps);
if(err != KErrNone)
{
ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
caps.iCallControlCaps=iCaps; // None of the extended caps are supported.
caps.iCallEventCaps=0;
ReqCompleted(aTsyReqHandle,KErrNone);
return KErrNone;
}
TInt CSimCall::NotifyMobileCallCapsChange(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps)
/**
* Register a client's interest in being notified when the RMobileCall capabilities change.
* @param aTsyReqHandle The TSY handle associated with this request.
* @param aCaps The capability structure that will be populated with the new capability
* information.
* @return TInt Standard error code.
*/
{
__ASSERT_ALWAYS(!iNotifyMobileCapsChange.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));
iNotifyMobileCapsChange.iNotifyPending=ETrue;
iNotifyMobileCapsChange.iNotifyHandle=aTsyReqHandle;
iNotifyMobileCapsChange.iNotifyData=aCaps;
return KErrNone;
}
TInt CSimCall::NotifyMobileCallCapsChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancel a client's interest in being notified when the RMobileCall capabilities change.
*/
{
if(iNotifyMobileCapsChange.iNotifyPending)
{
iNotifyMobileCapsChange.iNotifyPending=EFalse;
ReqCompleted(iNotifyMobileCapsChange.iNotifyHandle,KErrCancel);
}
return KErrNone;
}
TInt CSimCall::NotifyHookChange(const TTsyReqHandle aTsyReqHandle, RCall::THookStatus* aHookStatus)
/**
* Record a client's interst in being notified when the hook changes state.
*
* @param aTsyReqHandle Tsy Request handle for the client request
* @param aHookStatus pointer to the hook status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyHookChange");
iNotifyHookChange.iNotifyPending = ETrue;
iNotifyHookChange.iNotifyHandle = aTsyReqHandle;
iNotifyHookChange.iNotifyData = aHookStatus;
LOGCALL1("<<CSimCall::NotifyHookChange");
return KErrNone;
}
TInt CSimCall::NotifyHookChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancel a client's interest in being notified when the hook state changes.
*
* @param aTsyReqHandle Tsy Request handle for the client cancel request
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyHookChangeCancel");
if(iNotifyHookChange.iNotifyPending)
{
iNotifyHookChange.iNotifyPending=EFalse;
ReqCompleted(iNotifyHookChange.iNotifyHandle,KErrCancel);
}
LOGCALL1("<<CSimCall::NotifyHookChangeCancel");
return KErrNone;
}
TInt CSimCall::NotifyMobileCallStatusChange(const TTsyReqHandle aTsyReqHandle,RMobileCall::TMobileCallStatus* aStatus)
/**
* Record a client's interest in being notified when the call status changes.
* First check that there isn't already a notification pending (the ETel Server should protect
* against this) and then record the information necessary to complete the request later, when
* the status does actually change.
*
* @param aTsyReqHandle Tsy Request handle for the client request
* @param aStatus pointer to the call status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyMobileCallStatusChange");
__ASSERT_ALWAYS(!iMobileNotifyStatusChange.iNotifyPending,SimPanic(ENotificationAlreadyPending));
iMobileNotifyStatusChange.iNotifyPending = ETrue;
iMobileNotifyStatusChange.iNotifyHandle = aTsyReqHandle;
iMobileNotifyStatusChange.iNotifyData = aStatus;
LOGCALL1("<<CSimCall::NotifyMobileCallStatusChange");
return KErrNone;
}
TInt CSimCall::NotifyMobileCallStatusChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancel a client's interest in being notified when the call status changes.
* This is acheived simply by resetting the flag that indicates a notification is pending.
*
* @param aTsyReqHandle Tsy Request handle for the client cancel request
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyMobileCallStatusChangeCancel");
if(iMobileNotifyStatusChange.iNotifyPending)
{
iMobileNotifyStatusChange.iNotifyPending=EFalse;
ReqCompleted(iMobileNotifyStatusChange.iNotifyHandle,KErrCancel);
}
LOGCALL1("<<CSimCall::NotifyMobileCallStatusChangeCancel");
return KErrNone;
}
TInt CSimCall::NotifyStatusChange(const TTsyReqHandle aTsyReqHandle,RCall::TStatus* aStatus)
/**
* Record a client's interest in being notified when the call status changes.
* First check that there isn't already a notification pending (the ETel Server should protect
* against this) and then record the information necessary to complete the request later, when
* the status does actually change.
*
* @param aTsyReqHandle Tsy Request handle for the client request
* @param aStatus pointer to the call status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyStatusChange");
__ASSERT_ALWAYS(!iNotifyStatusChange.iNotifyPending,SimPanic(ENotificationAlreadyPending));
iNotifyStatusChange.iNotifyPending = ETrue;
iNotifyStatusChange.iNotifyHandle = aTsyReqHandle;
iNotifyStatusChange.iNotifyData = aStatus;
LOGCALL1("<<CSimCall::NotifyStatusChange");
return KErrNone;
}
TInt CSimCall::NotifyStatusChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Cancel a client's interest in being notified when the call status changes.
* This is acheived simply by resetting the flag that indicates a notification is pending.
*
* @param aTsyReqHandle Tsy Request handle for the client cancel request
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyStatusChangeCancel");
if(iNotifyStatusChange.iNotifyPending)
{
iNotifyStatusChange.iNotifyPending=EFalse;
ReqCompleted(iNotifyStatusChange.iNotifyHandle,KErrCancel);
}
LOGCALL1("<<CSimCall::NotifyStatusChangeCancel");
return KErrNone;
}
TInt CSimCall::NotifyDurationChange(const TTsyReqHandle aTsyReqHandle,TTimeIntervalSeconds* aTime)
/**
* Record a client's interest in being notified when the call duration changes.
*
* @param aTsyReqHandle
* @param aTime
* @return KErrNone or symbian wide error code
*/
{
iCallDurationHandler->StartNotification(aTsyReqHandle, aTime);
return KErrNone;
}
TInt CSimCall::NotifyDurationChangeCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* Not Supported in this TSY
*/
{
iCallDurationHandler->StopNotification();
return KErrNone;
}
TInt CSimCall::GetInfo(const TTsyReqHandle aTsyReqHandle, RCall::TCallInfo* aCallInfo)
/**
* Retrieve the Call Information.
*
* @param aTsyReqHandle
* @param aCallInfo pointer to the call information to be returned to client
* @return KErrNone
*/
{
aCallInfo->iCallName.Copy(iName);
aCallInfo->iLineName.Copy(iLine->iLineName);
aCallInfo->iHookStatus=ConvertStateToHook(iState);
aCallInfo->iStatus=GetCoreCallStatus();
aCallInfo->iDuration=0;
ReqCompleted(aTsyReqHandle,KErrNone);
return KErrNone;
}
TInt CSimCall::GetMobileCallInfo(const TTsyReqHandle aTsyReqHandle, TDes8* aMobileCallInfo)
/**
* Retrieve the Mobile Call Information
*
* @param aTsyReqHandle
* @param aCallInfo pointer to the call information to be returned to client
* @return KErrNone
*/
{
RMobileCall::TMobileCallInfoV1Pckg* mobileCallInfoV1=(RMobileCall::TMobileCallInfoV1Pckg*)aMobileCallInfo;
RMobileCall::TMobileCallInfoV1& mobileCallInfo=(*mobileCallInfoV1)();
// Check that the data structure is supported by the simulated TSY version
TInt err = iPhone->CheckSimTsyVersion(mobileCallInfo);
if(err != KErrNone)
{
ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
TUint caps=Caps();
if(caps&RCall::KCapsVoice)
mobileCallInfo.iService=RMobilePhone::EVoiceService;
else if(caps&RCall::KCapsData)
mobileCallInfo.iService=RMobilePhone::ECircuitDataService;
else if(caps&RCall::KCapsFax)
mobileCallInfo.iService=RMobilePhone::EFaxService;
else
mobileCallInfo.iService=RMobilePhone::EServiceUnspecified;
mobileCallInfo.iValid=0x0;
mobileCallInfo.iStatus=iState;
mobileCallInfo.iCallName.Copy(iName);
mobileCallInfo.iLineName.Copy(iLine->iLineName);
LOGCALL2("CSimCall::GetMobileCallInfo request completed with %d",iState);
ReqCompleted(aTsyReqHandle,KErrNone);
return KErrNone;
}
RCall::TStatus CSimCall::GetCoreCallStatus()
/**
* Converts Multimode call status (RMobileCall::TMobileCallStatus) to
* Core call Status (RCall::TStatus)
*
* @return RCall::TStatus The core call status
*/
{
// All status enums with values of Disconnecting and below are identical in
// ETelMM and Core, so the mapping function is simple.
RCall::TStatus coreStatus;
if (iState <= RMobileCall::EStatusDisconnecting)
coreStatus = (RCall::TStatus)iState;
else
switch (iState)
{
case RMobileCall::EStatusReconnectPending:
case RMobileCall::EStatusHold:
coreStatus = RCall::EStatusConnected;
break;
case RMobileCall::EStatusWaitingAlternatingCallSwitch:
coreStatus = RCall::EStatusIdle;
break;
default:
coreStatus = RCall::EStatusUnknown;
break;
}
return coreStatus;
}
TInt CSimCall::GetStatus(const TTsyReqHandle aTsyReqHandle, RCall::TStatus* aCallStatus)
/**
* Return the current call state. (Core API request)
*
* @param aTsyReqHandle
* @param aCallStatus pointer to the call status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::GetStatus");
*aCallStatus=GetCoreCallStatus();
ReqCompleted(aTsyReqHandle,KErrNone);
LOGCALL1("<<CSimCall::GetStatus");
return KErrNone;
}
TInt CSimCall::GetMobileCallStatus(const TTsyReqHandle aTsyReqHandle, RMobileCall::TMobileCallStatus* aCallStatus)
/**
* Return the current call state. (Multimode API request)
*
* @param aTsyReqHandle
* @param aCallStatus pointer to the call status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::GetMobileCallStatus");
*aCallStatus=iState;
ReqCompleted(aTsyReqHandle,KErrNone);
LOGCALL1("<<CSimCall::GetMobileCallStatus");
return KErrNone;
}
TInt CSimCall::TransferOwnership(const TTsyReqHandle aTsyReqHandle)
/**
* Transfer call ownership
* Not supported in this version of the Simulator TSY
*/
{
ReqCompleted(aTsyReqHandle,KErrNotSupported);
return KErrNone;
}
TInt CSimCall::AcquireOwnership(const TTsyReqHandle aTsyReqHandle)
/**
* Acquires call ownership
* Not supported in this version of the Simulator TSY
*/
{
ReqCompleted(aTsyReqHandle,KErrNotSupported);
return KErrNone;
}
TInt CSimCall::AcquireOwnershipCancel(const TTsyReqHandle /*aTsyReqHandle*/)
/**
* cancel AcquireOwnership request
* Not supported in this version of the Simulator TSY
*/
{
return KErrNone;
}
TInt CSimCall::GetCallDuration(const TTsyReqHandle aTsyReqHandle, TTimeIntervalSeconds* aTime)
/**
* Retrieves the last call duration
* Not supported in this version of the Simulator TSY
*/
{
LOGCALL1(">>CSimCall::GetCallDuration");
iCallDurationHandler->GetDuration(aTime);
ReqCompleted(aTsyReqHandle,KErrNone);
LOGCALL1("<<CSimCall::GetCallDuration");
return KErrNone;
}
TInt CSimCall::RecoverDataPortAndRelinquishOwnership()
/**
* Recovers the comm port.
* This is a data call specific request so not supported here.
*/
{
return KErrNotSupported;
}
TInt CSimCall::GetFaxSettings(const TTsyReqHandle,RCall::TFaxSessionSettings*)
/**
* Retrieves the last fax settings
* Not supported in this version of the Simulator TSY
*/
{
return KErrNotSupported;
}
TInt CSimCall::SetFaxSettings(const TTsyReqHandle,const RCall::TFaxSessionSettings*)
/**
* Sets the fax settings
* Not supported in this version of the Simulator TSY
*/
{
return KErrNotSupported;
}
CTelObject* CSimCall::OpenNewObjectByNameL(const TDesC& /*aName*/)
/**
* Only Fax Calls can be opened from the Call object, KErrNotSupported is returned.
*/
{
User::Leave(KErrNotSupported);
return NULL;
}
CTelObject* CSimCall::OpenNewObjectL(TDes& /*aNewName*/)
/**
* Only Fax objects can be opened from the Call object, and we are not supporting fax calls
* in this TSY. KErrNotSupported is returned.
*/
{
User::Leave(KErrNotSupported);
return NULL;
}
TBool CSimCall::Used()
{
return (AccessCount()>1);
}
void CSimCall::SetUsed()
{
(void)Open();
}
void CSimCall::SetUnused()
{
Close();
}
TInt CSimCall::ChangeStateL(RMobileCall::TMobileCallStatus aNewState,TBool aSwap, TBool aNoPropagation)
/**
* Attempt to change state.
* First validate that the requested state change is ok. If it is then proceed to change
* the state and complete any pending state change notification.
*
* @param aState the new state to change to
* @param aSwap indicates that state change takes place as a consequence of swap operation on the call
* @param aNoPropagation indicates whether change propagate to the holder line object
* @return Error indication if change of state is successful or not
*/
{
LOGCALL3(">>CSimCall::ChangeState 0x%08x [newState=%d] entry", this,aNewState);
if(!aNoPropagation)
{
TInt ret=iLine->ChangeStateL(aNewState,aSwap,this);
if(ret!=KErrNone)
return ret;
}
// Check for call duration change
if (!iCallDurationHandler)
iCallDurationHandler=CSimCallDuration::NewL(this);
if ((iState != RMobileCall::EStatusConnected) && (iState != RMobileCall::EStatusHold) && (aNewState == RMobileCall::EStatusConnected))
iCallDurationHandler->StartDuration();
else if ((aNewState != RMobileCall::EStatusConnected) && (aNewState != RMobileCall::EStatusHold) && ((iState == RMobileCall::EStatusConnected) || (iState == RMobileCall::EStatusHold)))
iCallDurationHandler->StopDuration();
// Actually change the state.
iState=aNewState;
// Check for a pending state change notification (core)
if(iNotifyStatusChange.iNotifyPending)
{
iNotifyStatusChange.iNotifyPending=EFalse;
*(RCall::TStatus*)iNotifyStatusChange.iNotifyData=GetCoreCallStatus();
ReqCompleted(iNotifyStatusChange.iNotifyHandle,KErrNone);
}
// Check for a pending state change notification (multimode)
if(iMobileNotifyStatusChange.iNotifyPending)
{
iMobileNotifyStatusChange.iNotifyPending=EFalse;
*(RMobileCall::TMobileCallStatus*)iMobileNotifyStatusChange.iNotifyData=iState;
ReqCompleted(iMobileNotifyStatusChange.iNotifyHandle,KErrNone);
}
// Check for a pending hook change notification.
RCall::THookStatus hookStatus=ConvertStateToHook(iState);
if(iHookState!=hookStatus)
{
iHookState=hookStatus;
if(iNotifyHookChange.iNotifyPending)
{
iNotifyHookChange.iNotifyPending=EFalse;
*(RCall::THookStatus*)iNotifyHookChange.iNotifyData=iHookState;
ReqCompleted(iNotifyHookChange.iNotifyHandle,KErrNone);
}
}
// Check for a possible change in capabilities.
TUint caps=Caps();
if(iCaps!=caps)
{
iCaps=caps;
if(iNotifyCapsChange.iNotifyPending)
{
iNotifyCapsChange.iNotifyPending=EFalse;
((RCall::TCaps*)iNotifyCapsChange.iNotifyData)->iFlags=iCaps;
ReqCompleted(iNotifyCapsChange.iNotifyHandle,KErrNone);
}
if(iNotifyMobileCapsChange.iNotifyPending)
{
iNotifyMobileCapsChange.iNotifyPending=EFalse;
TPckg<RMobileCall::TMobileCallCapsV1>* mobileCallCapsPckg=(TPckg<RMobileCall::TMobileCallCapsV1>*)iNotifyMobileCapsChange.iNotifyData;
RMobileCall::TMobileCallCapsV1& mobileCallCaps=(*mobileCallCapsPckg)();
mobileCallCaps.iCallControlCaps=iCaps; // None of the extended caps are supported.
mobileCallCaps.iCallEventCaps=0;
ReqCompleted(iNotifyMobileCapsChange.iNotifyHandle,KErrNone);
}
}
if((aNewState == RMobileCall::EStatusConnected && !aSwap)|| aNewState == RMobileCall::EStatusDisconnecting)
iLine->UpdatePhoneNotifiers(this,aNewState);
LOGCALL2("<<CSimCall::ChangeState exit %d",iState);
return KErrNone;
}
void CSimCall::UpdateNotifiers()
/**
Update notifiers of other voice call when it gets swapped
*/
{
LOGCALL2(">>CSimCall::UpdateNotifiers 0x%08x entry", this);
// Check for call duration change
if (!iCallDurationHandler)
{
TRAP_IGNORE(iCallDurationHandler=CSimCallDuration::NewL(this));
}
// Check for a pending state change notification (core)
if(iNotifyStatusChange.iNotifyPending)
{
iNotifyStatusChange.iNotifyPending=EFalse;
*(RCall::TStatus*)iNotifyStatusChange.iNotifyData=GetCoreCallStatus();
ReqCompleted(iNotifyStatusChange.iNotifyHandle,KErrNone);
}
// Check for a pending state change notification (multimode)
if(iMobileNotifyStatusChange.iNotifyPending)
{
iMobileNotifyStatusChange.iNotifyPending=EFalse;
*(RMobileCall::TMobileCallStatus*)iMobileNotifyStatusChange.iNotifyData=iState;
ReqCompleted(iMobileNotifyStatusChange.iNotifyHandle,KErrNone);
}
// Check for a pending hook change notification.
RCall::THookStatus hookStatus=ConvertStateToHook(iState);
if(iHookState!=hookStatus)
{
iHookState=hookStatus;
if(iNotifyHookChange.iNotifyPending)
{
iNotifyHookChange.iNotifyPending=EFalse;
*(RCall::THookStatus*)iNotifyHookChange.iNotifyData=iHookState;
ReqCompleted(iNotifyHookChange.iNotifyHandle,KErrNone);
}
}
// Check for a possible change in capabilities.
TUint caps=Caps();
if(iCaps!=caps)
{
iCaps=caps;
if(iNotifyCapsChange.iNotifyPending)
{
iNotifyCapsChange.iNotifyPending=EFalse;
((RCall::TCaps*)iNotifyCapsChange.iNotifyData)->iFlags=iCaps;
ReqCompleted(iNotifyCapsChange.iNotifyHandle,KErrNone);
}
if(iNotifyMobileCapsChange.iNotifyPending)
{
iNotifyMobileCapsChange.iNotifyPending=EFalse;
TPckg<RMobileCall::TMobileCallCapsV1>* mobileCallCapsPckg=(TPckg<RMobileCall::TMobileCallCapsV1>*)iNotifyMobileCapsChange.iNotifyData;
RMobileCall::TMobileCallCapsV1& mobileCallCaps=(*mobileCallCapsPckg)();
mobileCallCaps.iCallControlCaps=iCaps; // None of the extended caps are supported.
mobileCallCaps.iCallEventCaps=0;
ReqCompleted(iNotifyMobileCapsChange.iNotifyHandle,KErrNone);
}
}
LOGCALL2("<<CSimCall::UpdateNotifiers exit %d",iState);
}
TInt CSimCall::ActionEvent(TCallEvent /*aEvent*/, TInt /*aStatus*/)
/**
* This is an empty shell function. Each line should implement its own
* state machine.
*/
{
return KErrNotSupported;
}
void CSimCall::GenerateCoreCallCaps(TUint& aCaps)
/**
* Populate the variable capabilities that are dependant upon the call state.
* @param TUint The capability variable that will be populated with the core capabilities.
*/
{
if(iState==RMobileCall::EStatusIdle)
aCaps |= RCall::KCapsDial;
if(iState==RMobileCall::EStatusConnected)
aCaps |= RCall::KCapsHangUp;
if((iLine->IsAnswerCallObjectSpare())&&(iState==RMobileCall::EStatusIdle))
aCaps |= RCall::KCapsAnswer;
}
void CSimCall::ResetIfRingingL()
{
if(iState==RMobileCall::EStatusRinging)
__ASSERT_ALWAYS(ChangeStateL(RMobileCall::EStatusIdle,EFalse,ETrue) == KErrNone, SimPanic(EGeneral));
}
void CSimCallDuration::TimerCallBack(TInt /*aId*/)
{
//increase duration by 1 sec
iCallDuration=static_cast<TTimeIntervalSeconds>(iCallDuration.Int()+1);
if(iNotifyDurationChange.iNotifyPending)
{
*(TTimeIntervalSeconds*)iNotifyDurationChange.iNotifyData=iCallDuration;
iNotifyDurationChange.iNotifyPending=EFalse;
iCall->ReqCompleted(iNotifyDurationChange.iNotifyHandle,KErrNone);
}
iDurationTimer->Start(1 , this);
}
CSimCallDuration* CSimCallDuration::NewL(CSimCall* aCall)
/**
* Standard two-phase constructor.
* @param aPhone The parent phone object.
* @return CSimCallDuration The new CallDuration class
*/
{
CSimCallDuration* self=new(ELeave) CSimCallDuration(aCall);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
CSimCallDuration::CSimCallDuration(CSimCall* aCall)
:iCallDuration(0),iCall(aCall)
/**
* Trivial first phase construction.
* @param aPhone The parent phone object.
*/
{
iNotifyDurationChange.iNotifyPending=EFalse;
iNotifyDurationChange.iNotifyData=0;
}
void CSimCallDuration::ConstructL()
{
iDurationTimer = CSimTimer::NewL(iCall->iLine->iPhone);
}
CSimCallDuration::~CSimCallDuration()
/**
* Standard destructor. Destroy the heap-based object owned by this object.
*/
{
if (iDurationTimer)
{
if (iDurationTimer->IsActive())
iDurationTimer->Cancel();
delete iDurationTimer;
}
}
void CSimCallDuration::StartDuration()
{
iCallDuration = 0;
iDurationTimer->Start(1 , this);
}
void CSimCallDuration::StopDuration()
{
if (iDurationTimer)
{
if (iDurationTimer->IsActive())
iDurationTimer->Cancel();
}
}
void CSimCallDuration::StartNotification(TTsyReqHandle aTsyReqHandle, TTimeIntervalSeconds* aTime)
{
__ASSERT_ALWAYS(!iNotifyDurationChange.iNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));
iNotifyDurationChange.iNotifyData=aTime;
iNotifyDurationChange.iNotifyPending=ETrue;
iNotifyDurationChange.iNotifyHandle=aTsyReqHandle;
}
void CSimCallDuration::StopNotification()
{
if(iNotifyDurationChange.iNotifyPending)
{
iNotifyDurationChange.iNotifyPending=EFalse;
iCall->ReqCompleted(iNotifyDurationChange.iNotifyHandle,KErrCancel);
}
}
void CSimCallDuration::GetDuration(TTimeIntervalSeconds* aTime)
{
*aTime = iCallDuration;
}
CSimCallRemotePartyInfoChange* CSimCallRemotePartyInfoChange::NewL(CSimCall* aCall)
/**
* Standard two-phase constructor.
* @param aCall on upon remote party info is needed
* @return CSimCallRemotePartyInfoChange
*/
{
CSimCallRemotePartyInfoChange* self=new(ELeave) CSimCallRemotePartyInfoChange(aCall);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
CSimCallRemotePartyInfoChange::CSimCallRemotePartyInfoChange(CSimCall* aCall)
:iCall(aCall)
/**
* Trivial first phase construction.
* @param aCall is call object upon remote party info is needed.
*/
{
iNotifyRemotePartyInfo.iNotifyPending=EFalse;
iNotifyRemotePartyInfo.iNotifyData=0;
}
void CSimCallRemotePartyInfoChange::ConstructL()
{
iRemoteInfoTimer = CSimTimer::NewL(iCall->iLine->iPhone);
}
void CSimCallRemotePartyInfoChange::Start()
{
iRemoteInfoTimer->Start(iDelay, this);
}
CSimCallRemotePartyInfoChange::~CSimCallRemotePartyInfoChange()
/**
* Standard destructor. Destroy the heap-based object owned by this object.
*/
{
if (iRemoteInfoTimer)
{
if (iRemoteInfoTimer->IsActive())
iRemoteInfoTimer->Cancel();
delete iRemoteInfoTimer;
}
}
void CSimCallRemotePartyInfoChange::TimerCallBack(TInt /*aId*/)
{
if(iRemotePartyInfoV1.iRemoteIdStatus != RMobileCall::ERemoteIdentityUnknown && iNotifyRemotePartyInfo.iNotifyPending)
{
iNotifyRemotePartyInfo.iNotifyPending=EFalse;
*(RMobileCall::TMobileCallRemotePartyInfoV1*)iNotifyRemotePartyInfo.iNotifyData=iRemotePartyInfoV1;
iCall->ReqCompleted(iNotifyRemotePartyInfo.iNotifyHandle,KErrNone);
}
}
TInt CSimCall::NotifyRemotePartyInfoChange(const TTsyReqHandle aTsyReqHandle, TDes8* aRemoteParty)
/**
* Record a client's interest in being notified when the remote party info changes.
* First check that there isn't already a notification pending (the ETel Server should protect
* against this) and then record the information necessary to complete the request later, when
* the status does actually change.
*
* @param aTsyReqHandle Tsy Request handle for the client request
* @param aStatus pointer to the call status
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyRemotePartyInfoChange");
__ASSERT_ALWAYS(iNotifyRemotePartyInfoTimer, SimPanic(EOjectNotConstructed));
__ASSERT_ALWAYS(!iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyPending,SimPanic(ENotificationAlreadyPending));
RMobileCall::TMobileCallRemotePartyInfoV1Pckg* remotepartyPckg = (RMobileCall::TMobileCallRemotePartyInfoV1Pckg*) aRemoteParty;
RMobileCall::TMobileCallRemotePartyInfoV1& remoteparty = (*remotepartyPckg)();
// Check that the data structure is supported by the simulated TSY version
TInt err = iPhone->CheckSimTsyVersion(remoteparty);
if(err != KErrNone)
{
ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
//start timer
iNotifyRemotePartyInfoTimer->Start();
iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyPending = ETrue;
iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyHandle = aTsyReqHandle;
iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyData = &remoteparty;
LOGCALL1("<<CSimCall::NotifyRemotePartyInfoChange");
return KErrNone;
}
TInt CSimCall::NotifyRemotePartyInfoChangeCancel()
/**
* Cancel a client's interest in being notified when the remote party info changes.
* This is acheived simply by resetting the flag that indicates a notification is pending.
*
* @return KErrNone
*/
{
LOGCALL1(">>CSimCall::NotifyRemotePartyInfoChangeCancel");
if(iNotifyRemotePartyInfoTimer && iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyPending)
{
iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyPending=EFalse;
ReqCompleted(iNotifyRemotePartyInfoTimer->iNotifyRemotePartyInfo.iNotifyHandle,KErrCancel);
}
LOGCALL1("<<CSimCall::NotifyRemotePartyInfoChangeCancel");
return KErrNone;
}