cellular/telephonysettings/src/PSetCallDivertingDualAffectImpl.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 23:21:58 +0200
branchRCL_3
changeset 3 a4a774cb6ea7
parent 0 ff3b6d0fd310
child 43 7d48bed6ce0c
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* Copyright (c) 2008-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: Implementation of CPSetCallDivertingDualAffectImpl class.
*
*/


// INCLUDE FILES
#include "PSetCallDivertingDualAffectImpl.h"
#include "PSetSubscriberIdCheck.h"

#include <badesca.h>
#include <etelmm.h>
#include <e32math.h>
#include <vmnumber.h>
#include <e32svr.h>
#include <featmgr.h>
#include <centralrepository.h>
#include <settingsinternalcrkeys.h>

#include "PsetCallDiverting.h"
#include "PsetContainer.h"
#include "MPsetDivertObs.h"
#include "PsetTelephony.h"
#include "PSetPanic.h"
#include "MPsetRequestObs.h"
#include "PSetUtility.h"
#include "PhoneSettingsLogger.h"
#include "PsetSAObserver.h"

//  LOCAL CONSTANTS AND MACROS
_LIT( KPSetIntNbr, "+" );
_LIT( KPSNameOfClass, "CPsetCallDiverting" );
_LIT( KPhone, "Telephone" );

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CPSetCallDivertingDualAffectImpl::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CPSetCallDivertingDualAffectImpl* CPSetCallDivertingDualAffectImpl::NewL( 
        MPsetDivertObserver& aObserver, 
        RMobilePhone& aPhone,
        CPsetCallDiverting* aDivert )
    {
    CPSetCallDivertingDualAffectImpl* self = new ( ELeave ) CPSetCallDivertingDualAffectImpl( aPhone, aDivert );
    CleanupStack::PushL( self );
    self->ConstructL( aObserver );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CPSetCallDivertingDualAffectImpl::~CPSetCallDivertingDualAffectImpl
// ---------------------------------------------------------------------------
//
CPSetCallDivertingDualAffectImpl::~CPSetCallDivertingDualAffectImpl()
    {
    delete iIdCheck;
    }

// -----------------------------------------------------------------------------
// CPSetCallDivertingDualAffectImpl::CPSetCallDivertingDualAffectImpl
// C++ constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPSetCallDivertingDualAffectImpl::CPSetCallDivertingDualAffectImpl( 
                    RMobilePhone& aPhone, CPsetCallDiverting* aDivert ) : 
                    CPSetCallDivertingBase( aPhone, aDivert )
    {
    }

// -----------------------------------------------------------------------------
// CPSetCallDivertingDualAffectImpl::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::ConstructL( MPsetDivertObserver& aObserver )
    {
    CPSetCallDivertingBase::ConstructL( aObserver );
    
    iIdCheck = CPSetSubscriberIdCheck::NewL();
    }

// -----------------------------------------------------------------------------
// CPSetCallDivertingDualAffectImpl::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::SetDivertingL( const TCallDivertSetting& aDivert,  TBasicServiceGroups aBsc )
    { __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::SetDivertingL");
    __PHSLOGSTRING1("[PHS]    CPSetCallDivertingDualAffectImpl::SetDivertingL: aBsc: %d", aBsc );
    if ( IsActive() )
        {
        User::Leave( KErrInUse );
        } 
    CPsetTelephony::CheckLineModeL( aDivert.iServiceGroup, &iPhone, iLine );
    if ( !iLine->SubSessionHandle() )
        {
        User::Leave( KErrBadHandle );
        }
        
    SetRequestStatus( EPSetChangeDivert );
    iReason = PSetUtility::GetDivertReason ( aDivert.iCondition );
    iVoiceDivert = SetVoiceDivert( aDivert, aBsc );

    /* In case of SIM support dual activation and * -command has been issued from ALS 
    * line 2 we need to change the SS service 
    * code from SS_GSM_AUX_TELEPHONY to the SS_ALL_TELE_AND_BEARER 
    * at SS_SERVICE_REQ -message.
    */
    if ( ( aBsc == EAllTeleAndBearer ) &&                // Command affects to both lines
       ( iAls == ESSSettingsAlsAlternate ) &&            // Command given at ALS line 2
       ( (RThread().Name()).Compare( KPhone ) == 0 ) &&  // *# -commands are given only from Phone thread
       ( aDivert.iSetting != ECheckStatus ) &&           // Not interrogating
       ( iIdCheck->DoesSIMSupportDualActivation() ) )    // Check SIM/IMSI
        {
        // Set iBsc to same value as aBsc so that correct alsValue 
        // can be determined in GetSAAls() method.
        iBsc = aBsc;
        }
    else
        {
        // Set iBsc to same value as aBsc so that correct alsValue 
        // can be determined in GetSAAls() method.
        iBsc = aBsc;
        ValidateBsc( aBsc );
        }

    iPluralNotes = IsMultiAffectingDivert( aDivert, aBsc );

    //Copy data to member variable
    iChangeInfo.iNumber.iTelNumber.Copy( aDivert.iNumber );
    iChangeInfo.iTimeout = KPSetDefaultDelayTimeValue;
    if ( aBsc == EAltTele )
        {
        iChangeInfo.iServiceGroup = PSetUtility::VerifyAltLineUseL();
        }
    iChangeInfo.iServiceGroup = PSetUtility::ChangeToEtelInternal( aBsc ); 
    iChangeInfo.iNumber.iNumberPlan = RMobilePhone::EIsdnNumberPlan;
    iChangeInfo.iNumber.iTypeOfNumber = RMobilePhone::EUnknownNumber;
    if ( iChangeInfo.iNumber.iTelNumber.Length() > 0 )
        {
        if ( iChangeInfo.iNumber.iTelNumber.Left(1) == KPSetIntNbr )
            {
            iChangeInfo.iNumber.iTypeOfNumber = 
                RMobilePhone::EInternationalNumber;
            }
        }

    switch ( aDivert.iSetting )
        {
        case ERegisterDiverting:
            iChangeInfo.iAction = RMobilePhone::EServiceActionRegister;
            iChangeInfo.iTimeout = aDivert.iNoReplyTimer;
            __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::SetDivertingL: ERegisterDiverting" );
            break;
        case EEraseDiverting:
            iChangeInfo.iAction = RMobilePhone::EServiceActionErase;
            __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::SetDivertingL: EEraseDiverting" );
            break;
        case EActivateDiverting:
            iChangeInfo.iAction = RMobilePhone::EServiceActionActivate;
            iChangeInfo.iTimeout = aDivert.iNoReplyTimer;
            __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::SetDivertingL: EActivateDiverting" );
            break;
        case ECancelDiverting:
            iChangeInfo.iAction = RMobilePhone::EServiceActionDeactivate;
            __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::SetDivertingL: ECancelDiverting" );
            break;
        default:
            User::Leave( KErrArgument );
            break;
        }

    //Start requesting for setting Divert.
    iPhone.SetCallForwardingStatus( iStatus, iReason, iChangeInfo );
    StartRequestingL( KPsetRequestAlreadySet );    
    __PHSLOGSTRING("[PHS] <--CPSetCallDivertingDualAffectImpl::SetDivertingL" );
   }

// ---------------------------------------------------------------------------
// RunL
// ---------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::RunL()
    {
    __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::RunL" );
    
    __ASSERT_ALWAYS( 
        iObserver != NULL, Panic( KPSNameOfClass, ECDRequestPanicNoObserver ) );

    //Hide requesting note - does not leave when deleting a note.
    iObserver->SetEngineContact( iDivert );
    iObserver->HandleCFRequestingL( EFalse, EFalse );

    //Handle error case.
    if ( iStatus != KErrNone )
        {
        iObserver->HandleDivertingErrorL( iStatus.Int() );
        RequestCompleted( iStatus.Int() );
        return;
        }
        
    iDivertStatus.Initialize();
    switch ( iCurrentReq )
        {
        case EPSetChangeDivert:
            {
            __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::RunL: EPSetChangeDivert" );
            //Notify Observer            
            iDivertStatus.iStatus = PSetUtility::GetChangeInfoStatus( iChangeInfo.iAction );
            
             // Check is done because of VOIP notification functionality(PSetNotesUI).
            if ( iVoiceDivert )
                {
                iDivertStatus.iServiceGroup = EServiceGroupVoice;
                }
            
            iObserver->HandleDivertingChangedL( iDivertStatus, iPluralNotes );
            
            //Notify observer.
            HandleSANotificationL( 
                IsVMBXDivertL( iChangeInfo.iNumber.iTelNumber ), 
                iDivertStatus.iStatus );
            break;
            }
        case EPSetGetDivertStatus:
            {
            __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::RunL: EPSetGetDivertStatus" );

            CMobilePhoneCFList* cfList = iCfInterrogator->RetrieveListL();
            CleanupStack::PushL( cfList );
            CMobilePhoneCFList* cleanedList = CMobilePhoneCFList::NewL();            
            CleanupStack::PushL( cleanedList );
            
            TInt numOfItems = cfList->Enumerate();
            TInt index = 0;
            RMobilePhone::TMobilePhoneCFInfoEntryV1 cfEntry;
            RMobilePhone::TMobilePhoneCFInfoEntryV1 copy;
            iDivertStatus.iStatus = EDivertingStatusNotRegistered;
            while( index < numOfItems )
                {
                cfEntry = cfList->GetEntryL( index );
                iBsc = PSetUtility::ChangeToGSM( cfEntry.iServiceGroup );

                if ( cfEntry.iStatus == RMobilePhone::ECallForwardingStatusActive )
                    {
                    copy.iServiceGroup = cfEntry.iServiceGroup;
                    copy.iCondition = cfEntry.iCondition;
                    copy.iStatus = cfEntry.iStatus;
                    copy.iNumber = cfEntry.iNumber;
                    copy.iTimeout = cfEntry.iTimeout;
                    cleanedList->AddEntryL( copy );
                    }
                 __PHSLOGSTRING1("[PHS] CPSetCallDivertingDualAffectImpl::RunL: EPSetGetDivertStatus     iBsc: %d", iBsc );
                 __PHSLOGSTRING1("[PHS] CPSetCallDivertingDualAffectImpl::RunL: EPSetGetDivertStatus iStatus: %d", cfEntry.iStatus );
                 
                /* Basic Service Codes above were removed from "if" statement below because they would 
                * cause divert indicator to appear with Data services. Dual activation SIM doesnt want to show 
                * Divert indication for video service.*/                
                if ( iBsc == EAllTeleAndBearer || iBsc == EAllTele || iBsc == ETelephony || iBsc == EAltTele )
                    {
                    // iVoiceDivert is set to true to ensure that the icons are updated in every case.
                    iVoiceDivert = ETrue;
                    if ( ( cfEntry.iStatus != RMobilePhone::ECallForwardingStatusNotRegistered )
                        && ( cfEntry.iStatus != RMobilePhone::ECallForwardingStatusNotActive )
                        && ( cfEntry.iStatus != RMobilePhone::ECallForwardingStatusNotProvisioned ) )
                        {
                        iDivertStatus.iStatus = EDivertingStatusActive;
                        }
                    else
                        {
                        iDivertStatus.iStatus = EDivertingStatusNotRegistered;
                        }
                    
                    HandleSANotificationL( 
                            IsVMBXDivertL( cfEntry.iNumber.iTelNumber ), 
                            iDivertStatus.iStatus );
                    }
                index++;
                }
            if ( cleanedList->Enumerate() == 0 )
                {
                iObserver->HandleDivertingStatusL( *cfList, iPluralNotes );
                }
            else
                {
                iObserver->HandleDivertingStatusL( *cleanedList, iPluralNotes );
                }
            CleanupStack::PopAndDestroy( 2 ); //cleanedList, cfList
            cfList = NULL;
            cleanedList = NULL;
            iCFStatusCheck = EFalse; 
            break;
            }
        default:
            Panic( KPSNameOfClass, ECDRequestPanicIncorrectRequest );
            break;
        } 
    RequestCompleted( KErrNone );
    __PHSLOGSTRING("[PHS] <--CPSetCallDivertingDualAffectImpl::RunL" );
    }    

// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::DoCancel()
    {
    __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::DoCancel" );
    //Decide which request to cancel.
    switch( iCurrentReq )
        {
        case EPSetChangeDivert:
            __PHSLOGSTRING("[PHS]   DoCancel - EPSetChangeDivert" );
            iPhone.CancelAsyncRequest( EMobilePhoneSetCallForwardingStatus );
            break;
        case EPSetGetDivertStatus:
            __PHSLOGSTRING("[PHS]   DoCancel - EPSetGetDivertStatus" );
            iCfInterrogator->Cancel();
            delete iCfInterrogator;
            iCfInterrogator = NULL;
            break;
        default:
            break;
        }
    
    //Set current request to none.
    iCurrentReq = EPSetNone;
    iVoiceDivert = EFalse;
    __PHSLOGSTRING("[PHS]<-- CPSetCallDivertingDualAffectImpl::DoCancel" );
    }

// -----------------------------------------------------------------------------
// Called if RunL Leaves
// -----------------------------------------------------------------------------
//
TInt CPSetCallDivertingDualAffectImpl::RunError( TInt aError )
    {
    __PHSLOGSTRING1("[PHS]--> CPSetCallDivertingDualAffectImpl::RunError aError: %d", aError );
    if ( ( iCurrentReq == EPSetGetDivertStatus || iCurrentReq == EPSetChangeDivert)
         && iVoiceDivert )
        {
        __PHSLOGSTRING("[PHS]   RunError - HandleSANotificationL" );
        TRAP_IGNORE( HandleSANotificationL( EFalse, iDivertStatus.iStatus ) );
        }
        
    if ( iCurrentReq == EPSetGetDivertStatus )
        {
        iCFStatusCheck = EFalse;
        }   
    aError = KErrNone;
        
    //Set current request to none.
    iCurrentReq = EPSetNone;    
    iVoiceDivert = EFalse;
    __PHSLOGSTRING("[PHS]<-- CPSetCallDivertingDualAffectImpl::RunError" );
    return aError;  
    }

// ---------------------------------------------------------------------------
//  If unconditional voice divert is activated/cancelled, notifies observer, 
//  so that it can set on/off indicators.
// ---------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::HandleSANotificationL( 
    TBool aVmbxDivert, TDivertingStatus& aCfStatus )
    {
    __PHSLOGSTRING2("[PHS]--> CPSetCallDivertingDualAffectImpl::HandleSANotificationL aVmbxDivert: %d, aCfStatus: %d", aVmbxDivert, aCfStatus );
    TBool divertChanged = EFalse;
    //If divert is not with voice, do not touch indicators.
    if ( !iVoiceDivert )
        {
        return;
        }

    //Unconditional divert and all diverts
    if ( iReason == RMobilePhone::ECallForwardingUnconditional ||
        iReason == RMobilePhone::ECallForwardingAllCases )
        {
        if ( iCurrentReq == EPSetChangeDivert )
            {
            //show indicator if, activation/registration, else hide it
            //these are probably incorrect....
            divertChanged = 
                ( iChangeInfo.iAction == RMobilePhone::EServiceActionRegister ||
                  iChangeInfo.iAction == RMobilePhone::EServiceActionActivate);
            }
        else
            {
            //show indicator if status is activated, hide for cancelled.
            divertChanged = ( aCfStatus == EDivertingStatusActive );
            }
        }
    else
        {
        //if not unconditional, do not touch indicators.
        return;
        }
        
    CPsetSAObserver* systemObserver = CPsetSAObserver::NewL();
    CleanupStack::PushL( systemObserver );
    
    TUnconditionalCFStatus status(KCFIndicatorUnknown);
    
    User::LeaveIfError( systemObserver->GetCurrentDivertStatus( status ) );
    
    // If used SIM support dual activation and ALS is supported then do the check for
    // current divert information. 
    if ( ( iIdCheck->DoesSIMSupportDualActivation()  ) && 
         ( iAls != ( ENotSupportedLine ) ) ) 
        {
        SetCurrentDivertInformation( status, divertChanged );
        }
    
    TCallDivertNotifySetting setting = CreateDivertNotifySetting(
        status, divertChanged, aVmbxDivert, iBsc );
    
    // Notify observer that Diverts have changed.
    systemObserver->NotifyDivertChange( GetSAAls(), 
        setting,
        -1 );
        
    CleanupStack::PopAndDestroy( systemObserver );
    
    __PHSLOGSTRING("[PHS] <--CPSetCallDivertingDualAffectImpl::HandleSANotificationL" );
    }

// ---------------------------------------------------------------------------
// Sets current divert information if used used SIM supports dual activation.
// ---------------------------------------------------------------------------
//
void CPSetCallDivertingDualAffectImpl::SetCurrentDivertInformation( 
    TUnconditionalCFStatus& aStatus, 
    const TBool aDivertChanged )
    {
    TUnconditionalCFStatus previousDivertStatus = aStatus;
    TSelectedLine alsLine = GetSAAls();
    
    if (( iChangeInfo.iServiceGroup == RMobilePhone::EAllServices) &&    // - Service Code is All tele and bearer.
        ( iCurrentReq == EPSetChangeDivert) && (                         // - Change divert command issued.
        ( iReason == RMobilePhone::ECallForwardingUnconditional ) ||     // - CallForwardingCondition is: CFU or 
        ( iReason == RMobilePhone::ECallForwardingAllCases ) )  )        // CFA.                                           
        {
        switch ( alsLine )
            {
            case EPrimaryLine:
                {
                if( aDivertChanged )     // ON
                    {
                    if(( previousDivertStatus == KCFNoCallsForwarded ) ||      // None/Line1 -> Line2 -> Both
                       ( previousDivertStatus == ( KCFVoiceForwarded | KCFForwardedOnLine1 ) ))
                        {
                        aStatus = KCFForwardedOnLine2;
                        }
                    }
                else                    // OFF
                    {
                    if(( previousDivertStatus == ( KCFVoiceForwarded | KCFForwardedOnLine1 | KCFForwardedOnLine2 ) ) ||  // Both/Line2 -> Line1 -> None
                       ( previousDivertStatus == KCFForwardedOnLine2 ))
                        {
                        aStatus = static_cast<TUnconditionalCFStatus>( KCFVoiceForwarded | KCFForwardedOnLine1 );
                        }
                    }
                break;
                }

            case EAuxiliaryLine:
                {
                if( aDivertChanged )     // ON
                    {
                    if(( previousDivertStatus == KCFNoCallsForwarded ) ||      // None/Line2 -> Line 1 -> Both
                       ( previousDivertStatus == KCFForwardedOnLine2 ))
                        {
                        aStatus = static_cast<TUnconditionalCFStatus>( KCFVoiceForwarded | KCFForwardedOnLine1 );
                        }
                    }
                else                    // OFF
                    {
                    if(( previousDivertStatus == ( KCFVoiceForwarded | KCFForwardedOnLine1 | KCFForwardedOnLine2 ) ) ||  // Both/Line1 -> Line 2 -> None
                       ( previousDivertStatus == ( KCFVoiceForwarded | KCFForwardedOnLine1 ) ))
                        {
                        aStatus = KCFForwardedOnLine2;
                        }
                    }
                break;
                }

            default:
                break;
            }
        }    
    }

// ---------------------------------------------------------------------------
// Returns ETrue if divert operation is to voice or to all operations.
// ---------------------------------------------------------------------------
//
TBool CPSetCallDivertingDualAffectImpl::SetVoiceDivert( 
        const TCallDivertSetting& aDivert,
        const TBasicServiceGroups /*aBsc*/ )
    {
    TBool retValue(EFalse);
    if ( aDivert.iServiceGroup == EServiceGroupVoice ||
         aDivert.iServiceGroup == EServiceGroupAllTeleservices)
        {
        retValue = ETrue;
        }
    return retValue;
    }

// ---------------------------------------------------------------------------
// Gets Als information.
// ---------------------------------------------------------------------------
//
TSelectedLine CPSetCallDivertingDualAffectImpl::GetSAAls()
    {
    __PHSLOGSTRING("[PHS]--> CPSetCallDivertingDualAffectImpl::GetSAAls" );
    __PHSLOGSTRING2("[PHS] iAls: %d iBsc: %d", iAls, iBsc  );
    TSelectedLine alsValue = ENotSupportedLine;
    switch ( iAls )
        {
        case ESSSettingsAlsNotSupported:
            alsValue = ENotSupportedLine;
            break;
        case ESSSettingsAlsPrimary:
            iChangeInfo.iServiceGroup == RMobilePhone::EAuxVoiceService 
                ? ( alsValue = EAuxiliaryLine )  
                : ( alsValue = EPrimaryLine );
            break;
        case ESSSettingsAlsAlternate:
            iChangeInfo.iServiceGroup == RMobilePhone::EAuxVoiceService 
                ? ( alsValue = EAuxiliaryLine )  
                : ( alsValue = EPrimaryLine );
            break;
        default:
            alsValue = ENotSupportedLine;
            break;
        }
    
    // If user checks/activates divert to line which is not selected currently than we have
    // to change returned alsvalue accordinly, if this is not done divert icon status is updated to wrong status.
    // Example case: Line 2 active user activates divert to line 1: **21*phonenumber*11#.
    if ( iBsc == EAltTele && iAls == ESSSettingsAlsPrimary )
        {
        __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::GetSAAls - Line 2 divert activation/check from Line 1" );
        alsValue = EAuxiliaryLine;
        }
    else if ( iBsc == ETelephony && iAls == ESSSettingsAlsAlternate )
        {
        __PHSLOGSTRING("[PHS]    CPSetCallDivertingDualAffectImpl::GetSAAls - Line 1 divert activation/check from Line 2" );
        alsValue = EPrimaryLine;
        }
    
    __PHSLOGSTRING1("[PHS]    CPSetCallDivertingDualAffectImpl::GetSAAls: alsValue: %d", alsValue );
    __PHSLOGSTRING("[PHS] <--CPSetCallDivertingDualAffectImpl::GetSAAls" );
    return alsValue;
    }

// End of File