--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gssettingsuis/Gs/GSCallDivertPlugin/Src/GSCallDivertModel.cpp Thu Nov 04 13:38:47 2010 +0800
@@ -0,0 +1,598 @@
+/*
+* Copyright (c) 2008 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: Model for call divert functionality. Tries to encapsulate
+* most of hw/engine related functionality from UI components.
+*
+*/
+
+
+
+
+// User includes:
+#include "featmgr.h"
+#include "GSCallDivertModel.h"
+#include "GSCallDivertView.h"
+#include "GsLogger.h"
+#include "GSPhoneSettingConstants.h"
+
+
+// System includes:
+#include <CPbkContactEngine.h>
+#include <CPhCltUssd.h>
+#include <MPsetDivertObs.h>
+#include <PhCltTypes.h>
+#include <PsetContainer.h>
+#include <PsuiContainer.h>
+#include <RPhCltServer.h>
+#include <RSSSettings.h>
+#include <centralrepository.h>
+#include <NumberGroupingCRKeys.h>
+#include <NumberGrouping.h>
+
+// Constants for restricted call divert
+const TInt KMaxLengthSendString = 40;
+_LIT( KOne, "1" );
+_LIT( KAsterisk, "*" );
+_LIT( KHashMark, "#" );
+_LIT( KOneHundredTwenty, "120" );
+
+// Class neme descriptor for panic descriptions
+_LIT( KGSCallDivertModel, "CGSCallDivertModel" );
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::CGSCallDivertModel
+// ---------------------------------------------------------------------------
+CGSCallDivertModel::CGSCallDivertModel()
+{
+}
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::NewL
+// ---------------------------------------------------------------------------
+CGSCallDivertModel* CGSCallDivertModel::NewL()
+{
+ CGSCallDivertModel* self = new( ELeave ) CGSCallDivertModel;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+}
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::ConstructL
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::ConstructL()
+{
+ iContactEngine = CPbkContactEngine::NewL();
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ iBasicClient = CPhCltUssd::NewL();
+ }
+ iSettings = CPsetContainer::NewL();
+ iObsContainer = CPsuiContainer::NewL();
+ iCfObserver = iObsContainer->CreateCFObsL();
+ iForward = iSettings->CreateCFObjectL( *iCfObserver );
+ iSsSettings = new (ELeave) RSSSettings;
+ User::LeaveIfError( iSsSettings->Open() );
+}
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::~CGSCallDivertModel
+// ---------------------------------------------------------------------------
+CGSCallDivertModel::~CGSCallDivertModel()
+{
+ // These objects have to be deleted in specific order or otherwise a access
+ // violation will follow. So, if changing order, be very careful and test
+ // thoroughly.
+ delete iContactEngine;
+ delete iObsContainer;
+ delete iCfObserver;
+ delete iForward;
+ delete iSettings;
+ if (FeatureManager::FeatureSupported ( KFeatureIdRestrictedCallDivert ) )
+ {
+ delete iBasicClient;
+ }
+ if( iSsSettings )
+ {
+ iSsSettings->Close ( );
+ delete iSsSettings;
+ }
+ if( iNumberGroupingRepository )
+ {
+ delete iNumberGroupingRepository;
+ iNumberGroupingRepository = NULL;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::SendCallDivertRequestL
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::SendCallDivertRequestL(
+ TCallDivertSetting& aCallDivertSetting,
+ RMobilePhone::TMobilePhoneServiceAction aInfo,
+ TBool& aVmbxDivert,
+ TInt aCommand,
+ TGSCallDivertServices aDivertService )
+ {
+ // Set Delay time if necessary.
+ TInt retVal = KCFNoNeedToGetTimeValue;
+
+ //User is doing activation
+ if ( aCallDivertSetting.iSetting == EActivateDiverting )
+ {
+ if ( aCallDivertSetting.iNumber == KNullDesC )
+ {
+ return; //User started to activate, but cancelled.
+ }
+ //Delay time needs to be set for no answer, not available.
+ if ( aDivertService == ECFDivertWhenNoAnswer ||
+ aDivertService == ECFDivertWhenNotAvailable )
+ {
+ retVal = iDivertView->CreateTimeListL();
+ }
+ }
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ // Always ask for duration if it's restricted call divert
+ retVal = iDivertView->CreateTimeListL();
+ }
+ //Call Phonesettings if all values have been set.
+ if ( retVal )
+ {
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ __GSLOGSTRING( "[CGSCallDivertModel::SendCallDivertRequestL] -- Sending restricted call divert request: --" );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCallDivertSetting.iNumber:%S", &aCallDivertSetting.iNumber );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] iDivertServiceGroup: %d", iDivertServiceGroup );
+
+ ActivateRestrictedCallDivertL( aCallDivertSetting.iNumber );
+ }
+ else
+ {
+ __GSLOGSTRING( "[CGSCallDivertModel::SendCallDivertRequestL] -- Sending call divert request: --" );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCallDivertSetting.iNumber:%S", &aCallDivertSetting.iNumber );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aInfo: %d", aInfo );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aVmbxDivert: %d", aVmbxDivert );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aCommand: %d", aCommand );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] aDivertService: %d", aDivertService );
+ __GSLOGSTRING1( "[CGSCallDivertModel::SendCallDivertRequestL] iDivertServiceGroup: %d", iDivertServiceGroup );
+
+ // Make a call to PhoneSettings.
+ EngineOperatorL( aCallDivertSetting, aInfo, aVmbxDivert, aCommand, aDivertService, iDivertServiceGroup );
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::EngineOperatorL
+//
+// Seems to be a blocking function...
+// Handles the engine operating, arguments tell what to call and
+// the number if needed.
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::EngineOperatorL(
+ TCallDivertSetting& aDivert,
+ const RMobilePhone::TMobilePhoneServiceAction& aInfo,
+ TBool& aVmbxValidNumber,
+ TInt aCommand,
+ TGSCallDivertServices aDivertService,
+ TGSCallDivertServiceGroups aDivertServiceGroup )
+ {
+ __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] Start...");
+
+ TBasicServiceGroups bsc = EAllTeleAndBearer;
+ aDivert.iNoReplyTimer = 0;
+
+ if ( aCommand == ECFCmdCancelAll )
+ {
+ aDivert.iCondition = EDivertConditionAllCalls;
+ aDivert.iSetting = EEraseDiverting;
+ aDivert.iStatus = EDivertingStatusUnknown;
+ aDivert.iServiceGroup = EServiceGroupAllTeleservices;
+ aDivert.iNumber.Zero();
+ iForward->SetDivertingL( aDivert, bsc );
+
+ __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] ECFCmdCancelAll");
+ return;
+ }
+
+ SetDivertParametersL( aDivert, bsc, aDivertService, aDivertServiceGroup );
+ __GSLOGSTRING1("[CGSCallDivertModel::EngineOperatorL] ServiceGroup: %d", bsc);
+
+ switch ( aInfo )
+ {
+ case RMobilePhone::EServiceActionUnspecified:
+ iForward->GetDivertingStatusL( aDivert.iServiceGroup,
+ aDivert.iCondition,
+ bsc );
+ break;
+ case RMobilePhone::EServiceActionActivate:
+ aDivert.iSetting = EActivateDiverting;
+ iForward->SetDivertingL( aDivert, bsc, aVmbxValidNumber );
+ break;
+ case RMobilePhone::EServiceActionErase:
+ aDivert.iSetting = EEraseDiverting;
+ iForward->SetDivertingL( aDivert, bsc );
+ break;
+ case RMobilePhone::EServiceActionDeactivate:
+ aDivert.iSetting = ECancelDiverting;
+ iForward->SetDivertingL( aDivert, bsc );
+ break;
+ case RMobilePhone::EServiceActionRegister:
+ aDivert.iSetting = ERegisterDiverting;
+ iForward->SetDivertingL( aDivert, bsc, aVmbxValidNumber );
+ break;
+ default:
+ Panic ( KGSCallDivertModel, EInvalidDivertAction );
+ break;
+ }
+ __GSLOGSTRING("[CGSCallDivertModel::EngineOperatorL] End.");
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::VoiceMailActivationL
+//
+// Handles activation attempts to voicemail box.
+// ---------------------------------------------------------------------------
+TInt CGSCallDivertModel::VoiceMailActivationL( TDes& aTelNumber )
+ {
+ __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] aTelNumber: %S", &aTelNumber);
+ TRAPD( err, iForward->VoiceMailQueryL( aTelNumber ) );
+ if ( err )
+ {
+ __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] err=%d", err);
+ // If application is killed via FSW, contact selection query
+ // returns KLeaveExit. This should propagate to "root"
+ // application where it reaches the active scheduler loop
+ // and thus allows proper application exit when the loop exits.
+ // Therefore propagate the error to caller and do not ignore it.
+ if ( KLeaveExit == err )
+ {
+ __GSLOGSTRING("[CGSCallDivertModel::VoiceMailActivationL] KLeaveExit");
+ User::Leave( err );
+ }
+ return KErrCancel;
+ }
+ //Vmbx number can be "invalid" from CF point of view, because they are allowed to
+ //contain special characters. These must be removed before making a divert to the
+ //vmbx number.
+ //E.g. number +35850888#45 becomes +35850888 (end is dropped).
+ TInt noOfInvalidChars = KCFInvalidChars().Length();
+
+ for ( TInt index = 0; index < noOfInvalidChars; index++ )
+ {
+ RemoveSpecialChar( aTelNumber, KCFInvalidChars().Mid( index, 1 ) );
+ }
+ __GSLOGSTRING1("[CGSCallDivertModel::VoiceMailActivationL] aTelNumber: %S", &aTelNumber);
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::VideoMailActivationL
+//
+// Handles activation attempts to videomail box.
+// ---------------------------------------------------------------------------
+TInt CGSCallDivertModel::VideoMailActivationL( TDes& aTelNumber )
+ {
+ __GSLOGSTRING1("[CGSCallDivertModel::VideoMailActivationL] aTelNumber: %S", &aTelNumber);
+ // Trapped to return KErrCancel in all cases in order to provide same
+ // behaviour as in VoiceMailActivationL method (Both methods can be used
+ // in the same manner)
+ TRAPD( err, iForward->VideoMailQueryL( aTelNumber ) );
+ if ( err )
+ {
+ return KErrCancel;
+ }
+ //Vmbx number can be "invalid" from CF point of view, because they are allowed to
+ //contain special characters. These must be removed before making a divert to the
+ //vmbx number.
+ //E.g. number +35850888#45 becomes +35850888 (end is dropped).
+ TInt noOfInvalidChars = KCFInvalidChars().Length();
+ TPtrC invalidChars( KCFInvalidChars );
+ for ( TInt index = 0; index < noOfInvalidChars; index++ )
+ {
+ RemoveSpecialChar( aTelNumber, TPtrC( &invalidChars[ index ] ) );
+ }
+ __GSLOGSTRING1("[CGSCallDivertModel::VideoMailActivationL] aTelNumber: %S", &aTelNumber);
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::ActivateRestrictedCallDivertL
+//
+// Handles attempts to activate call divert in restricted mode
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::ActivateRestrictedCallDivertL(
+ TTelNumber& aDivertNumber )
+ {
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ //Send Number and ringing time to network by using USSD.
+ HBufC* sendString = HBufC::NewLC( KMaxLengthSendString );
+ TPtr ptr = sendString->Des();
+
+ //Start call forwarding has following syntax:
+ //*120*SI1*SI2*SI3 # SEND(Start & Set CF number & Set the time (sec.))
+ //where: S1 = 1
+ //SI2:(CF number)
+ //SI3: 0 - 120(ringing time (sec.))
+ ptr.Append( KAsterisk );
+ ptr.Append( KOneHundredTwenty );
+ ptr.Append( KAsterisk );
+ ptr.Append( KOne );
+ ptr.Append( KAsterisk );
+ ptr.Append( aDivertNumber );
+ ptr.Append( KAsterisk );
+ ptr.AppendNum( iForward->GetTimerValueL() );
+ ptr.Append( KHashMark );
+
+ iBasicClient->SendUssd( *sendString );
+ CleanupStack::PopAndDestroy( sendString );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::CheckStatusRestrictedCallDivertL
+//
+// Handles attempts to check divert status in restricted mode
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::CheckStatusRestrictedCallDivertL()
+ {
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ //Check call forwarding: * # 120*SI1 # SEND
+ HBufC* sendString = HBufC::NewLC( KMaxLengthSendString );
+ TPtr ptr = sendString->Des();
+ ptr.Append( KAsterisk );
+ ptr.Append( KHashMark );
+ ptr.Append( KOneHundredTwenty );
+ ptr.Append( KAsterisk );
+ ptr.Append( KOne );
+ ptr.Append( KHashMark );
+ iBasicClient->SendUssd( *sendString );
+ CleanupStack::PopAndDestroy( sendString );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::CancelRestrictedCallDivertL
+//
+// Handles attempts to cancel call divert in restricted mode
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::CancelRestrictedCallDivertL()
+ {
+ if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
+ {
+ //Cancel call forwarding: # 120*SI1 # SEND
+ HBufC* sendString = HBufC::NewLC( KMaxLengthSendString );
+ TPtr ptr = sendString->Des();
+ ptr.Append( KHashMark );
+ ptr.Append( KOneHundredTwenty );
+ ptr.Append( KAsterisk );
+ ptr.Append( KOne );
+ ptr.Append( KHashMark );
+ iBasicClient->SendUssd( *sendString );
+ CleanupStack::PopAndDestroy( sendString );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::SetDivertParametersL
+//
+// Sets parameters for EngineOperator function
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::SetDivertParametersL(
+ TCallDivertSetting& aDivert,
+ TBasicServiceGroups& aBsc,
+ TGSCallDivertServices aDivertService,
+ TGSCallDivertServiceGroups aDivertServiceGroup )
+ {
+ aDivert.iStatus = EDivertingStatusUnknown;
+ //complains for ambiguous definition of EUnknown
+ //need to correct in PhoneSettings.
+ aBsc = ( TBasicServiceGroups )-1;
+
+ if ( aDivertServiceGroup == EGSSettIdVoiceDivert )
+ {
+ aDivert.iServiceGroup = EServiceGroupVoice;
+ }
+ else
+ {
+ aDivert.iServiceGroup = EServiceGroupData;
+ aBsc = EAllBearer;
+ }
+
+ switch ( aDivertService )
+ {
+ case ECFDivertVoiceCalls:
+ {
+ aDivert.iCondition = EDivertConditionUnconditional;
+ TInt alsLine = ESSSettingsAlsNotSupported;
+ TInt alsError = iSsSettings->Get( ESSSettingsAls, alsLine );
+ if ( alsLine == ESSSettingsAlsNotSupported || ( alsLine == ESSSettingsAlsPrimary ) )
+ {
+ // Etelephony only activates voice service nothing else or causes
+ // voice service status request.
+ aBsc = ETelephony;
+ }
+ else // ESSSettingsAlsAlternate
+ {
+ // EAltTele only activates alternate service nothing else or causes
+ // alternate service status request.
+ aBsc = EAltTele;
+ }
+ break;
+ }
+ case ECFDivertWhenBusy:
+ aDivert.iCondition = EDivertConditionBusy;
+ break;
+ case ECFDivertWhenNoAnswer:
+ aDivert.iCondition = EDivertConditionNoReply;
+ aDivert.iNoReplyTimer = iForward->GetTimerValueL();
+ break;
+ case ECFDivertWhenOutOfReach:
+ aDivert.iCondition = EDivertConditionNotReachable;
+ break;
+ case ECFDivertWhenNotAvailable:
+ aDivert.iCondition = EDivertConditionAllConditionalCases;
+ aDivert.iNoReplyTimer = iForward->GetTimerValueL();
+ break;
+ case ECFDivertVideoCalls:
+ aBsc = EAllBearer;
+ aDivert.iCondition = EDivertConditionUnconditional;
+ break;
+ default:
+ Panic ( KGSCallDivertModel, EInvalidCurrentItem );
+ break;
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::MatchNumberToContactLC
+//
+// Returns the contact name matching the number, or the number if
+// no contact name is found.
+// Pushes the found (i.e. returned) name into Cleanupstack.
+// @see CContactDatabase::MatchPhoneNumberL(const TDesC&,const TInt)
+// ---------------------------------------------------------------------------
+HBufC* CGSCallDivertModel::MatchNumberToContactLC( const TDesC& aTelNum )
+ {
+ CContactIdArray* idArray = iContactEngine->MatchPhoneNumberL(
+ aTelNum,
+ KCFCharactersToMatch );
+ CleanupStack::PushL( idArray );
+ HBufC* contactTitle = NULL;
+ // fill data only if only single match is found
+ TInt matches = idArray->Count();
+ TBool conflict = EFalse;
+ if ( matches >= KCFSingleContact )
+ {
+ //several matches, have to check that id is the same
+ if ( matches != KCFSingleContact )
+ {
+ for ( TInt i = 1 ; i < matches ; i++ )
+ {
+ //all have to have same ID
+ if ( (*idArray)[i] != (*idArray)[0] )
+ {
+ conflict = ETrue;
+ break; //stop comparing
+ }
+ }
+ }
+ //Contact names are only shown if single match with same ID.
+ if ( !conflict )
+ {
+ CPbkContactItem* pbkItem =
+ iContactEngine->ReadContactLC( ( *idArray )[0] );
+ contactTitle = iContactEngine->GetContactTitleL( *pbkItem );
+ CleanupStack::PopAndDestroy( pbkItem );
+ }
+ }
+ CleanupStack::PopAndDestroy( idArray );
+ CleanupStack::PushL( contactTitle );
+ if( contactTitle )
+ {
+ __GSLOGSTRING1("[CGSCallDivertModel::MatchNumberToContactLC] contactTitle: %S", &contactTitle);
+ }
+ return contactTitle;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Removes a special character from vmbx number.
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::RemoveSpecialChar( TDes& aVmbxNumber,
+ const TDesC& aSpecChar )
+ {
+ TInt location = aVmbxNumber.Find( aSpecChar );
+ if ( location != KErrNotFound )
+ {
+ aVmbxNumber = aVmbxNumber.Left( location );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::DivertHandler
+// ---------------------------------------------------------------------------
+CPsetCallDiverting* CGSCallDivertModel::DivertHandler()
+ {
+ return iForward;
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::SetDivertView
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::SetDivertView( CGSCallDivertView* aDivertView )
+ {
+ iDivertView = aDivertView;
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::CGSCallDivertModel
+// ---------------------------------------------------------------------------
+TGSCallDivertServiceGroups CGSCallDivertModel::DivertServiceGroup()
+ {
+ return iDivertServiceGroup;
+ }
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::SetDivertServiceGroup
+// ---------------------------------------------------------------------------
+void CGSCallDivertModel::SetDivertServiceGroup(
+ TGSCallDivertServiceGroups aDivertServiceGroup )
+ {
+ iDivertServiceGroup = aDivertServiceGroup;
+ __GSLOGSTRING1( "[CGSCallDivertModel::SetDivertServiceGroup] aDivertServiceGroup:%d ",
+ aDivertServiceGroup )
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// CGSCallDivertModel::NumberGroupingSupportedL
+//
+// ---------------------------------------------------------------------------
+TBool CGSCallDivertModel::NumberGroupingSupportedL()
+ {
+ TInt numberGroupingVal;
+ TBool retVal = EFalse;
+ if( !iNumberGroupingRepository )
+ {
+ iNumberGroupingRepository = CRepository::NewL( KCRUidNumberGrouping );
+ }
+ iNumberGroupingRepository->Get( KNumberGrouping, numberGroupingVal );
+ switch( numberGroupingVal )
+ {
+ case CPNGNumberGrouping::ENumberGroupingDisabled:
+ retVal = EFalse;
+ break;
+ case CPNGNumberGrouping::ENumberGroupingEnabled:
+ retVal = ETrue;
+ break;
+ default:
+ retVal = EFalse;
+ break;
+ }
+ return retVal;
+ }
+