gssettingsuis/Gs/GSCallDivertPlugin/Src/GSCallDivertView.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:20:44 +0100
branchRCL_3
changeset 25 7e0eff37aedb
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2002-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:  Main view handling for Call Divert.
*
*/


// INCLUDE FILES
#include "GSCallDivertContainer.h"
#include "GSCallDivertModel.h"
#include "GSCallDivertQuery.h"
#include "GSCallDivertView.h"
#include "GsLogger.h"
#include "GSPhoneSettingConstants.h"
#include "GSRestrictedDivertContainer.h"
#include "LocalViewId.h"


#include <AiwContactSelectionDataTypes.h>
#include <AiwGenericParam.h>
#include <aknnotewrappers.h>        //for AknErrorNote
#include <AknUtils.h>
#include <aknViewAppUi.h>
#include <CPbk2SortOrderManager.h>
#include <CPbk2StoreConfiguration.h>
#include <CPbkContactItem.h>
#include <CPbkSingleItemFetchDlg.h>
#include <CVPbkContactLinkArray.h>
#include <CVPbkContactManager.h>
#include <featmgr.h>
#include <gscommon.hrh>
#include <gsfwviewuids.h>          // for restricted call forward
#include <gscalldivertpluginrsc.rsg>
#include <MPbk2ContactNameFormatter.h>
#include <MVPbkContactFieldData.h>
#include <MVPbkContactFieldTextData.h>
#include <MVPbkContactLink.h>
#include <MVPbkContactOperationBase.h>
#include <MVPbkContactStoreList.h>
#include <MVPbkStoreContact.h>
#include <NumberGrouping.h>         // for Number Grouping
#include <Pbk2ContactNameFormatterFactory.h>
#include <PsetCallDiverting.h>
#include <PsuiConstants.h>
#include <RPbkViewResourceFile.h>
#include <AiwServiceHandler.h>
#include <coeaui.h>
#include <CVPbkContactStoreUriArray.h>
#include <CVPbkFieldTypeSelector.h>
#include <hlplch.h>                 // for Help Launcher
#include <hlplch.h>             // For HlpLauncher
#include <RVPbkContactFieldDefaultPriorities.h>
#include <StringLoader.h>
#include <VPbkContactViewFilterBuilder.h>
#include <voicemailboxdomaincrkeys.h>
#include <centralrepository.h>

using namespace AiwContactAssign;

// LOCAL CONSTANTS
_LIT( KGSDivertClassName, "CGSCallDivertView" );

_LIT( KCallDivertInvalidchars, " ()" );

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

// ---------------------------------------------------------------------------
// CGSCallDivertView::CGSCallDivertView
//
// C++ constructor.
// ---------------------------------------------------------------------------
CGSCallDivertView::CGSCallDivertView( CGSCallDivertModel* aModel )
    : iModel( aModel )
    {
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::ConstructL
//
// Symbian OS two-phased constructor.
// ---------------------------------------------------------------------------
void CGSCallDivertView::ConstructL()
    {
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
            {
            iModel->SetDivertServiceGroup( EGSSettIdVoiceDivert );
            }
    iModel->SetDivertView( this );

    iStoresOpened = EFalse;
    iNumberFetchedAsynchronously = EFalse;

    BaseConstructL( R_CF_DIV_VIEW );

    iTitles = iCoeEnv->ReadDesCArrayResourceL( R_TITLE_ARRAY );
    iRockerPress = EFalse;

    //Check video mailbox suppport from cenrep
    //Since it is static feature, needs to be checked only once
    CRepository* videoMailboxRepository = 
                        CRepository::NewLC( KCRUidVideoMailbox );
    videoMailboxRepository->Get( KVideoMbxSupport, iVideoMailboxSupported );
    CleanupStack::PopAndDestroy( videoMailboxRepository );

    // AIW for pbk2 contact selection functionality. Construct contact manager
    // with the same store configuration as in Phonebook currently.
    iServiceHandler = CAiwServiceHandler::NewL();
    iServiceHandler->AttachL( R_CALL_DIVERT_CONTACT_SELECTION_INTEREST );
    CPbk2StoreConfiguration* configuration = CPbk2StoreConfiguration::NewL();
    CleanupStack::PushL( configuration );
    CVPbkContactStoreUriArray* uriArray = configuration->CurrentConfigurationL();
    CleanupStack::PushL( uriArray );
    iContactManager = CVPbkContactManager::NewL( *uriArray );
    iContactManager->ContactStoresL().OpenAllL( *this );
    CleanupStack::PopAndDestroy( uriArray );
    CleanupStack::PopAndDestroy( configuration );
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::~CGSCallDivertView
//
// Destructor.
// ---------------------------------------------------------------------------
CGSCallDivertView::~CGSCallDivertView()
    {
    if ( iTitles )
        {
        delete iTitles;
        }
    if( iRetrieveOperation )
        {
        delete iRetrieveOperation;
        iRetrieveOperation = NULL;
        }
    if( iContactLinks )
        {
        delete iContactLinks;
        iContactLinks = NULL;
        }
    
    TRAP_IGNORE
        (
        if( iContactManager )
            {
            iContactManager->ContactStoresL().CloseAll( *this );
            iStoresOpened = EFalse;
            delete iContactManager;
            }
        );
    delete iServiceHandler;


    if( iContextMenuItems )
    	{
    	delete iContextMenuItems;
    	iContextMenuItems = NULL;
    	}
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::NewLC
//
// 1st phase constructor.
// ---------------------------------------------------------------------------
CGSCallDivertView* CGSCallDivertView::NewLC( CGSCallDivertModel* aModel )
    {
    CGSCallDivertView* self;
    self = new ( ELeave ) CGSCallDivertView( aModel );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::NewContainerL
//
// Creates new iContainer.
// ---------------------------------------------------------------------------
void CGSCallDivertView::NewContainerL()
    {
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
        {
        iContainer = new (ELeave) CGSRestrictedDivertContainer();
        }
    else
        {
        iContainer = new (ELeave) CGSCallDivertContainer(
                     iModel->DivertServiceGroup() );
        }
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::Id
//
// implementation of the frameworks virtual function, closely related with view
// architecture and has little or no relevance here
// ---------------------------------------------------------------------------
TUid CGSCallDivertView::Id() const
    {
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
        {
        return KCallDivertPluginId;
        }
    else
        {
        return KCallDivertViewId;
        }
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::HandleCommandL
//
// Handles the received commands
// ---------------------------------------------------------------------------
void CGSCallDivertView::HandleCommandL( TInt aCommand )
    {
    iVoiceMailboxDivert = EFalse;
    TBool sendRequest = EFalse;
    RMobilePhone::TMobilePhoneServiceAction info =
        RMobilePhone::EServiceActionRegister;
    TCallDivertSetting divertRequest;

    if ( aCommand != ECFCmdCancelAll && iContainer )
        {
        if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
            {
            CGSRestrictedDivertContainer& container =
                *static_cast<CGSRestrictedDivertContainer*>( iContainer );
            iCurrentItem = container.CurrentFeatureId();
            }
        else
            {
            CGSCallDivertContainer& container =
                *static_cast<CGSCallDivertContainer*>( iContainer );
            iCurrentItem = container.CurrentFeatureId();
            }
        __GSLOGSTRING1("[CGSCallDivertView::HandleCommandL] iCurrentItem: %d", iCurrentItem);

        __ASSERT_ALWAYS( iCurrentItem != KErrNotFound, Panic( KGSDivertClassName,
                                                              EInvalidCurrentItem ) );
        }

    switch ( aCommand )
        {
        case EGSCmdAppChange:
            iRockerPress = EFalse;
            if ( iContainer )
            	{
            	HandleListBoxEventL( iContainer->iListBox, EEventEnterKeyPressed );
            	}            
            break;
        case EAknSoftkeyBack:
            if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
                {
                iAppUi->ActivateLocalViewL( KGSTelPluginUid );
                }
            else
                {
                iAppUi->ActivateLocalViewL( KCallDivertPluginId );
                }
            break;
        case EAknSoftkeyExit:
            AppUi()->HandleCommandL( EEikCmdExit );
            break;
        case ECFCmdActivate:
            divertRequest.iSetting = EActivateDiverting;
            info = RMobilePhone::EServiceActionRegister;

            // Activate depends on the selected call type (voice/data/fax)
            switch( iModel->DivertServiceGroup() )
                {
                case EGSSettIdVoiceDivert:
                    // Handle voice divert. Fetch used numbers and show it in query.
                    ExecuteDivertQueryL(
                        divertRequest.iNumber,
                        iTitles->MdcaPoint( iCurrentItem ),
                        iVoiceMailboxDivert );
                    sendRequest = ETrue;
                    break;
                case EGSSettIdVideoDivert:
                    if( iVideoMailboxSupported )
                        {
                        // Fetch used data divert number and show it in query.
                        ExecuteDivertQueryL(
                                divertRequest.iNumber,
                                iTitles->MdcaPoint( iCurrentItem ),
                                iVoiceMailboxDivert );
                        sendRequest = ETrue;
                        }
                    else
                        {
                        DisplayDataCallDivertNumberQueryL( divertRequest.iNumber );
                        sendRequest = ETrue;
                        }
                    break;
                default:
                    User::Panic( KGSDivertClassName, KErrArgument );
                    break;
                }
            break;
        case ECFCmdCancel:
            if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
                {
                sendRequest = EFalse;
                iModel->CancelRestrictedCallDivertL();
                }
            else
                {
                sendRequest = ETrue;
                divertRequest.iSetting = ECancelDiverting;
                info = RMobilePhone::EServiceActionErase;
                }
            break;
        case ECFCmdCheckStatus:
            if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
                {
                sendRequest = EFalse;
                iModel->CheckStatusRestrictedCallDivertL();
                }
            else
                {
                sendRequest = ETrue;
                divertRequest.iSetting = ECheckStatus;
                info = RMobilePhone::EServiceActionUnspecified;
                }
            break;
        case ECFCmdCancelAll:
            sendRequest = ETrue;
            divertRequest.iSetting = EEraseDiverting;
            info = RMobilePhone::EServiceActionErase;
            break;
        case EAknCmdHelp:
            {
            if( FeatureManager::FeatureSupported( KFeatureIdHelp ) )
                {
                HlpLauncher::LaunchHelpApplicationL(
                    iEikonEnv->WsSession(), iAppUi->AppHelpContextL() );
                }
            break;
            }
        default:
            iAppUi->HandleCommandL( aCommand );
            break;
        }

    // If a request needs to be sent.
    if ( sendRequest )
        {
        // will not divert in case empty number
        iModel->SendCallDivertRequestL( divertRequest,
                                        info,
                                        iVoiceMailboxDivert,
                                        aCommand,
                                        (TGSCallDivertServices) iCurrentItem );
        }
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::HandleListBoxSelectionL
//
// Handles List box selection
// ---------------------------------------------------------------------------
void CGSCallDivertView::HandleListBoxSelectionL()
    {
    iRockerPress = ETrue;
    CEikMenuBar* menuBar = MenuBar();
    if ( iRockerPress )
        {
        menuBar->SetMenuTitleResourceId( R_CF_MENUBAR_OPTIONS_VIEW );
        menuBar->SetMenuType( CEikMenuBar::EMenuContext );
        }
    else
        {
        menuBar->SetMenuTitleResourceId( R_CF_MENUBAR_DIV_VIEW );
        menuBar->SetMenuType( CEikMenuBar::EMenuOptions );
        }

    // Display menu bar.
    menuBar->TryDisplayMenuBarL();

    // Reset menu type to original default (EMenuOptions).
    menuBar->SetMenuType( CEikMenuBar::EMenuOptions );

    iRockerPress = EFalse;
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::ExecuteDivertQueryL
//
// --> voice calls -> all voice calls -> activate -> this popup.
//                          OR
// --> video calls -> all video calls -> activate -> this popup.
//
// ---Example---
// All [voice/]video calls:
// To [voice/]video mailbox
// [050512345678]
// [543454545435]
// [342343242343]
// To other number
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::ExecuteDivertQueryL( TTelNumber& aTelNumber,
                                             const TPtrC& aTitle,
                                             TBool& aVmbxValidNumber )
    {
    __GSLOGSTRING("[CGSCallDivertView::ExecuteDivertQueryL]");

    CAknSinglePopupMenuStyleListBox* list =
        new ( ELeave ) CAknSinglePopupMenuStyleListBox;
    CleanupStack::PushL( list );

    CDesC16ArrayFlat* defNumbers =
        new ( ELeave ) CDesC16ArrayFlat( KCFDefaultNumbers );
    CleanupStack::PushL( defNumbers );

    CAknPopupList* divertPopup =
        CAknPopupList::NewL( list, R_AVKON_SOFTKEYS_OK_CANCEL__OK );
    CleanupStack::PushL( divertPopup );

    list->ConstructL( divertPopup,CEikListBox::ELeftDownInViewRect );
    list->CreateScrollBarFrameL( ETrue );
    list->ScrollBarFrame()->SetScrollBarVisibilityL(
        CEikScrollBarFrame::EOff,
        CEikScrollBarFrame::EAuto );
    divertPopup->SetTitleL( aTitle );
    if( iContextMenuItems )
    	{
    	delete iContextMenuItems;
    	iContextMenuItems = NULL;
    	}
    iContextMenuItems = new ( ELeave ) CDesCArrayFlat( KCFMaxNrOfTargets );
    if( iModel->DivertServiceGroup() == EGSSettIdVoiceDivert )
        {
        CreateVoiceDivertItemsL( *iContextMenuItems, *defNumbers );
        }
    else
        {
        CreateVideoDivertItemsL( *iContextMenuItems );
        }
    __GSLOGSTRING2( "[CGSCallDivertView::ExecuteDivertQueryL] ItemCount: %d, defNumCount: %d",
                    iContextMenuItems->Count(),
                    defNumbers->Count() );
    CTextListBoxModel* model = list->Model();
    model->SetItemTextArray( iContextMenuItems );
    model->SetOwnershipType( ELbmDoesNotOwnItemArray );

    // Executeld handles the events in the list
    TBool modified = divertPopup->ExecuteLD();
    __GSLOGSTRING1("[CGSCallDivertView::ExecuteDivertQueryL] modified: %d", modified);
    CleanupStack::Pop(); //voiceDivertPopup

    if ( modified )
        {
        if( iModel->DivertServiceGroup() == EGSSettIdVoiceDivert )
            {
            aTelNumber = HandleVoiceDivertSelectionL( *list,
                                                      *defNumbers,
                                                      aVmbxValidNumber );
            }
        else
            {
            aTelNumber = HandleVideoDivertSelectionL( *list );
            }
        }
    __GSLOGSTRING1( "[CGSCallDivertView::ExecuteVoiceDivertQueryL] aTelNumber: %S",
                    &aTelNumber);
    CleanupStack::PopAndDestroy( 2 ); //defNumbers, list
    __GSLOGSTRING( "[CGSCallDivertView::ExecuteVoiceDivertQueryL] End." );
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::HandleVoiceDivertSelectionL
//
// Handles user's choice in the Target list.
// ---------------------------------------------------------------------------
TTelNumber CGSCallDivertView::HandleVoiceDivertSelectionL(
    CAknSinglePopupMenuStyleListBox& aList,
    CDesC16ArrayFlat& aDefNumbers,
    TBool& aVmbxDivert )
    {
    __GSLOGSTRING("[CGSCallDivertView::HandleVoiceDivertSelectionL] Start...");
    TTelNumber telNumber;
    telNumber.Zero();
    TInt index = aList.CurrentItemIndex();
    __GSLOGSTRING1("[CGSCallDivertView::HandleVoiceDivertSelectionL] index: %d", index);

    if ( index == KCFDivertToMailBox )
        {
        if ( iModel->VoiceMailActivationL( telNumber ) == KErrNone )
            {
            if ( telNumber == KNullDesC )
                {
                ShowErrorNoteL();
                }
            aVmbxDivert = ETrue;
            }
        }
    //To other number - make a dataquery
    else if ( index == ( aList.Model()->NumberOfItems() - 1 ) )
        {
        ExecuteDivertNumberQueryL( telNumber, R_TEXT_PRMPT_NUMBER );
        __GSLOGSTRING1("[CGSCallDivertView::HandleVoiceDivertSelectionL] telNumber: %S", &telNumber);

        UpdateDefaultVoiceDivertNumbersL( telNumber );
        }
    //To pre-defined default number
    else
        {
        telNumber = aDefNumbers.MdcaPoint( index - 1 );
        iModel->DivertHandler()->SwapDefaultNumberL( index );
        }
    __GSLOGSTRING("[CGSCallDivertView::HandleVoiceDivertSelectionL] End.");
    return telNumber;
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::HandleVideoDivertSelectionL
//
// Handles user's choice in the video Target list.
// ---------------------------------------------------------------------------
TTelNumber CGSCallDivertView::HandleVideoDivertSelectionL(
    CAknSinglePopupMenuStyleListBox& aList )
    {
    __GSLOGSTRING("[GSCallDivertView::HandleVideoDivertSelectionL] Start");
    TTelNumber telNumber( 0 );
    TInt index = aList.CurrentItemIndex();
    if ( index == KCFDivertToMailBox )
        {
        if ( iModel->VideoMailActivationL( telNumber ) == KErrNone )
            {
            if ( telNumber == KNullDesC )
                {
                ShowErrorNoteL();
                }
            }
        }
    else if( index == ( aList.Model()->NumberOfItems() - 1 ) )
        { // To other number - make a dataquery (Last item in list)
        DisplayDataCallDivertNumberQueryL( telNumber );
        __GSLOGSTRING1("[GSCallDivertView::HandleVideoDivertSelectionL] telNumber: %S", &telNumber );
        }
    __GSLOGSTRING("[GSCallDivertView::HandleVideoDivertSelectionL] Finished");
    return telNumber;
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::DisplayDataCallDivertNumberQueryL
//
// Displays data call number query and sets call divert
// ---------------------------------------------------------------------------
void CGSCallDivertView::DisplayDataCallDivertNumberQueryL( TTelNumber& aTelNumber )
    {
    aTelNumber = *iModel->DivertHandler()->GetUsedDataNumberLC();
    ExecuteDivertNumberQueryL( aTelNumber, R_TEXT_PRMPT_DATA_NUMBER );
    if( aTelNumber != KNullDesC )
        {
        iModel->DivertHandler()->SetUsedDataNumberL( aTelNumber );
        }
    CleanupStack::PopAndDestroy(); // aTelNumber from GetUsedDataNumberLC()
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::ExecuteDivertNumberQueryL
//
// Executes general number query dialog used by all diverts (voice/data/fax)
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::ExecuteDivertNumberQueryL( TDes& aValue, TInt aType )
    {
    TBool accepted = EFalse;
    while ( !accepted )
        {
        RemoveInvalidChars( aValue ); 
        if ( aValue.Length() > KGSMaxDataLength )
            {
            //Chop the first extra digits and keep the last KGSMaxDataLength
            //digits intact. This is according to the spec.
            aValue.Delete( 0, aValue.Length() - KGSMaxDataLength );
            }

        __GSLOGSTRING1("[CGSCallDivertView]    ExecuteDivertNumberQueryL: aValue: %S", &aValue);

        if( AknTextUtils::DigitModeQuery( AknTextUtils::EDigitModeEditorDefault ) )
            {
            AknTextUtils::DisplayTextLanguageSpecificNumberConversion( aValue );
            }
        CGSCallDivertQuery* query = CGSCallDivertQuery::NewL( aValue,
            CAknQueryDialog::ENoTone,
            R_AVKON_SOFTKEYS_OK_CANCEL__OK, R_CF_SOFTKEYS_SEARCH_CANCEL );
        CleanupStack::PushL( query );
        SetPromptToQueryL( *query, aType );
        TInt queryAction = query->ExecuteLD( R_DATA_QUERY );
        CleanupStack::Pop( query );
        AknTextUtils::ConvertDigitsTo( aValue, EDigitTypeWestern );
        switch ( queryAction )
            {
            case EAknSoftkeySearch:
                if( iStoresOpened )
                    {
                    // Reset the number selection because 'search' is selected.
                    aValue.Zero();
                    StartAsyncPhoneNumberFetchL();
                    accepted = ETrue;// Change to asynchronous mode
                    }
                break;
            case EAknSoftkeyOk:
                accepted = ETrue;
                if ( ValidatePhoneNumberL( aValue ) > KCFValidPhoneNumber ||
                     aValue.Length() == 0 )
                    {
                    accepted = EFalse;
                    }
                if ( iNumberFetchedAsynchronously )
                	{
                	switch( iModel->DivertServiceGroup() )
                	    {
                	    case EGSSettIdVoiceDivert:
                        	UpdateDefaultVoiceDivertNumbersL( aValue );
                        	break;
                	    case EGSSettIdVideoDivert:
                            {
                	        TTelNumber dataNumber( aValue );// Convert to TTelNumber
                	        iModel->DivertHandler()->SetUsedDataNumberL( dataNumber );
                	        break;
                            }
                	    default:
                	        break;
                	    }
                	iNumberFetchedAsynchronously = EFalse;
                	}
                break;
            case EAknSoftkeyBack:
            case EAknSoftkeyCancel:
            default:
                accepted = ETrue;
                aValue.Zero();
                break;
            }
        }
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::StartAsyncPhoneNumberFetchL
//
// Fetches values from phonebook ASYNCHRONOUSLY (pbk2 requirement).
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::StartAsyncPhoneNumberFetchL()
    {
    TUint fetchFlags = 0;

    // Construct empty filter
    CVPbkFieldTypeSelector* contactViewFilter =
                            CVPbkFieldTypeSelector::NewL(iContactManager->FieldTypes());
    CleanupStack::PushL(contactViewFilter);

    // Append the filter object with suitable criteria (only contacts with
    // phone number shown)
    VPbkContactViewFilterBuilder::BuildContactViewFilterL(*contactViewFilter,
                              EVPbkContactViewFilterPhoneNumber, *iContactManager);
    RVPbkContactFieldDefaultPriorities array;
    CleanupClosePushL(array);

    TAiwSingleItemSelectionDataV3 data = TAiwSingleItemSelectionDataV3();
    // Details selection shows only phone numbers
    data.SetAddressSelectType(EAiwPhoneNumberSelect);
    data.SetDefaultPriorities(array);
    // Contact list shows only contacts that have phone number(s)
    data.SetFetchFilter(contactViewFilter);
    data.SetFlags(fetchFlags);

    CAiwGenericParamList& inParamList = iServiceHandler->InParamListL();
    TAiwGenericParam param(EGenericParamContactSelectionData,
                     TAiwVariant(TAiwSingleItemSelectionDataV3Pckg(data)));
    inParamList.AppendL(param);

    iServiceHandler->ExecuteServiceCmdL(
            KAiwCmdSelect,
            inParamList,
            iServiceHandler->OutParamListL(),
            0,
            this);

    CleanupStack::PopAndDestroy(); // array
    CleanupStack::PopAndDestroy( contactViewFilter );
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::ValidatePhoneNumberL
//
// Puts a single resource string into a list.
// ---------------------------------------------------------------------------
TInt CGSCallDivertView::ValidatePhoneNumberL( const TDesC& aDivertTo )
    {
    TInt enteredNumber = KErrNone;
    TInt noOfInvalidChars = KCFInvalidChars().Length();

    // Plus is a special case, as it is accepted as first character.
    // FindPlus returns KCFErrIllegalNumber(1) if the number is not
    // acceptable.
    enteredNumber += FindPlus( aDivertTo );
    for ( TInt index = 0; index < noOfInvalidChars; index++ )
        {
        enteredNumber += aDivertTo.Find(
            KCFInvalidChars().Mid( index, 1 ) );
        }
    // Find returns KErrNotFound(-1), if character(s) is not found.
    // Therefore, after four searches for special characters in the
    // number, all results that have greater than -5 as result are not
    // acceptable.
    if ( enteredNumber > KCFValidPhoneNumber )
        {
        ShowErrorNoteL();
        __GSLOGSTRING( "[CGSCallDivertView::ValidatePhoneNumberL] Invalid phone number. " );
        }
    return enteredNumber;
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::AppendDelayItemL
//
// Appends items to delay time list.
// ---------------------------------------------------------------------------
void CGSCallDivertView::AppendDelayItemL( CDesCArrayFlat& aArrayToAppend,
                                          TInt aIndex )
    {
    //Delay times are defined as 5,10,15,20,25,30.
    //Append each of these to a list.
    TInt delaySeconds = KCFDelayStep * ( aIndex + 1);
    HBufC* string = StringLoader::LoadLC( R_TEXT_SLIST_SECONDS, delaySeconds );

    TPtr bufPtr = string->Des();
    if( AknTextUtils::DigitModeQuery( AknTextUtils::EDigitModeShownToUser ) )
        {
        AknTextUtils::LanguageSpecificNumberConversion( bufPtr );
        }
    aArrayToAppend.AppendL( *string );
    CleanupStack::PopAndDestroy( string );
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::CreateVoiceDivertItemsL
//
// Creates items for the targert list.
// ---------------------------------------------------------------------------
void CGSCallDivertView::CreateVoiceDivertItemsL(
    CDesCArray& aItems,
    CDesC16ArrayFlat& aDefaultNumbers )
    {
    HBufC* item = StringLoader::LoadLC( R_TEXT_DIVERT_TO_VOICE_MAIL );
    aItems.AppendL( *item );
    CleanupStack::PopAndDestroy( item );
    ReadDefaultVoiceDivertNumbersL( aItems, aDefaultNumbers );
    HBufC* string = StringLoader::LoadLC( R_TEXT_DIVERT_TO_NUMBER );
    aItems.AppendL( *string );
    CleanupStack::PopAndDestroy( string );
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::CreateVideoDivertItemsL
//
// Creates items for the data target list.
// ---------------------------------------------------------------------------
void CGSCallDivertView::CreateVideoDivertItemsL( CDesCArray& aItems )
    {
    HBufC* item = StringLoader::LoadLC( R_QTN_SS_DIVERT_TO_VIDEO_MAILBOX );
    aItems.AppendL( *item );
    CleanupStack::PopAndDestroy( item );
    HBufC* string = StringLoader::LoadLC( R_QTN_SS_DIVERT_VCALL_TO_OTHER_NUMBER );
    aItems.AppendL( *string );
    CleanupStack::PopAndDestroy( string );
    }


// ---------------------------------------------------------------------------
//
// Seeks '+' from given number. If '+' is first character, it is ignored.
//
// ---------------------------------------------------------------------------
TInt CGSCallDivertView::FindPlus( const TDesC& aDivertTo )
    {
    TInt seekPlus = aDivertTo.Find( KCFPlusSign );
    if ( seekPlus == KErrNotFound )
        {
        //no '+' in the number
        return KErrNone;
        }
    //first char '+', but there can additional '+'s
    if ( seekPlus == 0 )
        {
        //ignore first '+'
        TPtrC concat = aDivertTo.Right( aDivertTo.Length() - 1 );
        seekPlus = concat.Find( KCFPlusSign );
        if ( seekPlus != KErrNotFound )
            {
            return KCFErrIllegalNumber; //two '+'s in number
            }
        return KErrNone;
        }
    //'+' in number, but not first char
    else
        {
        return KCFErrIllegalNumber;
        }
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::SetPromptToQueryL
// Sets prompt to a query.
//
// ---------------------------------------------------------------------------
void CGSCallDivertView::SetPromptToQueryL( CGSCallDivertQuery& aQuery,
                                           const TInt& aType )
    {
    HBufC* title = StringLoader::LoadLC( aType );
    aQuery.SetPromptL( *title );
    CleanupStack::PopAndDestroy( title );
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::CreateDelayTimeItemsL
// Creates items for delay time list.
//
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::CreateDelayTimeItemsL( CDesCArrayFlat& aItems)
    {
    for ( TInt index = 0; index < KGSNrOfDelays; index++ )
        {
        AppendDelayItemL( aItems, index );
        }
    }


// ---------------------------------------------------------------------------
// CGSCallDivertView::CreateRestrictedCallDivertDelayTimeItemsL
// Creates items for Delay time list for restricted call divert.
//
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::CreateRestrictedCallDivertDelayTimeItemsL(
    CDesCArrayFlat& aItems )
    {
    // first item is 0 seconds
    AppendDelayItemL( aItems, -1);
    for ( TInt index = 0; index < KGSNrOfDelays; index++ )
        {
        AppendDelayItemL( aItems, index );
        }
    AppendDelayItemL( aItems, ( 60 / KCFDelayStep ) - 1);
    AppendDelayItemL( aItems, ( 90 / KCFDelayStep ) - 1);
    AppendDelayItemL( aItems, ( 120 / KCFDelayStep ) - 1);
    }

// -----------------------------------------------------------------------------
// CGSCallDivertView::ProcessCommandL
// -----------------------------------------------------------------------------
void CGSCallDivertView::ProcessCommandL( TInt aCommand )
    {
    MenuBar()->SetContextMenuTitleResourceId( R_CALL_DIVERT_MSK_CONTEXTMENUBAR );
    // Call base class
    CAknView::ProcessCommandL( aCommand );
    }


// ---------------------------------------------------------------------------
//
// Before showing a options menu, delete options key specific settings if
// rocker key has been pressed.
// ---------------------------------------------------------------------------
//
void CGSCallDivertView::DynInitMenuPaneL( TInt aResourceId,
                                          CEikMenuPane* aMenuPane )
    {
    TInt currentItem;
    CEikMenuBar* menuBar = MenuBar();
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
        {
        CGSRestrictedDivertContainer &container =
            *static_cast<CGSRestrictedDivertContainer*>( iContainer );
        currentItem = container.CurrentFeatureId();
        }
    else
        {
        CGSCallDivertContainer& container =
            *static_cast<CGSCallDivertContainer*>( iContainer );
        currentItem = container.CurrentFeatureId();
        }

    if ( aResourceId == R_CF_DIV_VIEW_MENU )
        {
        if (!menuBar->ItemSpecificCommandsEnabled() && menuBar->GetMenuType() == CEikMenuBar::EMenuOptions)
        	{
        	aMenuPane->SetItemDimmed( ECFCmdActivate, ETrue );
        	aMenuPane->SetItemDimmed( ECFCmdCancel, ETrue );
        	aMenuPane->SetItemDimmed( ECFCmdCheckStatus, ETrue );
        	}
        //remove help, if not supported from the main divert view
        //in this step, help is added to context menu too, which
        //is deleted in the next conditional stmt
        if ( FeatureManager::FeatureSupported ( KFeatureIdHelp ) )
            {
            aMenuPane->SetItemDimmed( EAknCmdHelp, EFalse );
            }
        else
            {
            aMenuPane->SetItemDimmed( EAknCmdHelp, ETrue );
            }

        if ( iRockerPress )
            {
            //remove Exit & Help from the menu
            aMenuPane->SetItemDimmed( EAknCmdExit, ETrue );
            aMenuPane->SetItemDimmed( EAknCmdHelp, ETrue );
            }
        else
            {
            iRockerPress = EFalse;
            }
        }

    if ( aResourceId == R_CF_MSK_DIV_VIEW_MENU ||
         aResourceId == R_CF_DIV_VIEW_MENU )
        {
        // when not available does not have check status
        if ( currentItem == ECFDivertWhenNotAvailable )
            {
            aMenuPane->SetItemDimmed( ECFCmdCheckStatus, ETrue );
            }
        }
    }

// ---------------------------------------------------------
// CGSCallDivertView::ShowErrorNote
//
// ---------------------------------------------------------
void CGSCallDivertView::ShowErrorNoteL()
    {
    HBufC* string = StringLoader::LoadLC( R_INVALID_NUMBER );
    CAknErrorNote* note = new ( ELeave ) CAknErrorNote ( ETrue );
    note->ExecuteLD( *string );
    CleanupStack::PopAndDestroy( string );
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::ReadDefaultVoiceDivertNumbersL
//
// Creates defcault items for the target list.
// ---------------------------------------------------------------------------
void CGSCallDivertView::ReadDefaultVoiceDivertNumbersL(
    CDesCArray& aItems,
    CDesC16ArrayFlat& aDefaultNumbers )
    {
    TInt amount = KErrNone;

    // this is for fetching name to a number from phonebook
    HBufC* defaultName = NULL;

    //Default numbers are fetched from shared data
    amount = iModel->DivertHandler()->GetDefaultNumbersL( aDefaultNumbers );
    __ASSERT_ALWAYS( amount == aDefaultNumbers.MdcaCount(),
        Panic( KGSDivertClassName, ECFDefaultNumberCountError ) );

    for ( TInt i = 0; i < amount; i++ )
        {
        //Default numbers should be checked, if there is a contact name associated
        // with it.
        defaultName = NULL;
        defaultName = iModel->MatchNumberToContactLC( aDefaultNumbers.MdcaPoint( i ) );
        __GSLOGSTRING1("[CGSCallDivertView]    ReadDefaultVoiceDivertNumbersL: defaultName: %S", &defaultName);
        if ( defaultName )
            {
            aItems.AppendL( *defaultName );
            }
        else
            {
            TTelNumber string;
            if ( iModel->NumberGroupingSupportedL() )
                {
                CPNGNumberGrouping* numberGrouping = CPNGNumberGrouping::NewL(
                    KPSUIMaxPSUIItemLength );
                CleanupStack::PushL( numberGrouping );

                if ( aDefaultNumbers.MdcaPoint( i ).Length() <=
                    numberGrouping->MaxDisplayLength() )
                    {
                    numberGrouping->Set( aDefaultNumbers.MdcaPoint( i ) );
                    string = numberGrouping->FormattedNumber();
                    }
                CleanupStack::PopAndDestroy( numberGrouping );
                }
            if ( !string.Length() )
                {
                string = aDefaultNumbers.MdcaPoint(i);
                }
            AknTextUtils::DisplayTextLanguageSpecificNumberConversion( string );
            aItems.AppendL( string );
            __GSLOGSTRING1("[CGSCallDivertView]    ReadDefaultVoiceDivertNumbersL: string: %S", &string);
            }
        CleanupStack::PopAndDestroy(); //defaultName
        }
    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::UpdateDefaultVoiceDivertNumbersL
//
// Updates most recently used numbers to cenrep
// ---------------------------------------------------------------------------
void CGSCallDivertView::UpdateDefaultVoiceDivertNumbersL(  TDes& aNumber )

    {
    if ( aNumber !=  KNullDesC && iContextMenuItems )
        {
        //If activation is done to already existing default number,
        //but using the "Other number" selection, this must be verified.
        HBufC* contactName = iModel->MatchNumberToContactLC( aNumber );

        TInt found = KErrNone;
        TInt loc = KErrNotFound;

        if ( contactName )
            {
            found = iContextMenuItems->Find( *contactName, loc );
            }
        else
            {
            found = iContextMenuItems->Find( aNumber, loc );
            }
        CleanupStack::PopAndDestroy(); //contactName

        if ( found > 0 ) //number is not part of current def.numbers
            {
            iModel->DivertHandler()->SetNewDefaultNumberL( aNumber );
            }
        else
            {
            iModel->DivertHandler()->SwapDefaultNumberL( loc );
            }
        }
    else
        {
        __GSLOGSTRING( "[CGSCallDivertView::UpdateDefaultVoiceDivertNumbersL] iContextMenuItems == NULL!!" );
        }

    }

// ---------------------------------------------------------------------------
// CGSCallDivertView::HandleNotifyL
//
// AIW callback function.
// ---------------------------------------------------------------------------
TInt CGSCallDivertView::HandleNotifyL(
    TInt aCmdId,
    TInt aEventId,
    CAiwGenericParamList& aEventParamList,
    const CAiwGenericParamList& /*aInParamList*/ )
    {
    TInt err = KErrNone;
    if( ( aCmdId == KAiwCmdSelect ) || ( aCmdId == KAiwCmdAssign ) )
        {
        if( aEventId == KAiwEventCompleted )
            {
            TInt index = 0;
            iNumberFetchedAsynchronously = ETrue;
            const TAiwGenericParam* param = aEventParamList.FindFirst(
                index, EGenericParamContactLinkArray );

            if( param && iStoresOpened )
                {
                if( iContactLinks )
                    {
                    delete iContactLinks;
                    iContactLinks = NULL;
                    }
                TPtrC8 contactLinks = param->Value().AsData();

                CVPbkContactLinkArray* localContactLinks =
                    CVPbkContactLinkArray::NewLC(
                    contactLinks,
                    iContactManager->ContactStoresL() );

                CleanupStack::Pop( localContactLinks );
                iContactLinks = localContactLinks;

                if( iContactLinks->Count() > 0 )
                    {
                    iRetrieveOperation = iContactManager->RetrieveContactL( iContactLinks->At( 0 ), *this );
                    }
                }
            }
        else if (aEventId == KAiwEventCanceled)
            {
            // Do nothing.
            }
        else if (aEventId == KAiwEventOutParamCheck)
            {
            // This is needed as PBK2 mysteriously crashes if check is not
            // acccepted. There's no actual need to check anything but to go
            // ahead here so setting to ETrue.
            err = ETrue;
            }
        else if (aEventId == KAiwEventQueryExit)
            {
            err = ETrue;
            }
        }
    return err;
    }


// --------------------------------------------------------------------------
// CGSCallDivertView::VPbkSingleContactOperationComplete
// --------------------------------------------------------------------------
//
void CGSCallDivertView::VPbkSingleContactOperationComplete(
    MVPbkContactOperationBase& /*aOperation*/,
    MVPbkStoreContact* aContact )
    {
    if( iRetrieveOperation )
        {
        delete iRetrieveOperation;
        iRetrieveOperation = NULL;
        }
    TRAP_IGNORE
        (
        MVPbkStoreContactField* field = aContact->Fields().RetrieveField( iContactLinks->At( 0 ) );
        if ( field && field->FieldData().DataType() == EVPbkFieldStorageTypeText )
            {
            // aContact has selected phone number from Pbk2 dialog. Set this as
            // a text for ExecuteDivertNumberQueryL.
            TCallDivertSetting setting;
            setting.iSetting = EActivateDiverting;
            setting.iNumber = MVPbkContactFieldTextData::Cast( field->FieldData() ).Text();

            //Ask for user input.
            ExecuteDivertNumberQueryL( setting.iNumber, R_TEXT_PRMPT_NUMBER );

            // ExecuteDivertNumberQueryL() will set setting.iNumber to KNullDesC if user
            // selected 'search'. In this case program execution is moved to
            // pbk2 asynchronous dialog and this function can exit without
            // sending call divert request.
            if( setting.iNumber != KNullDesC )
                {
                // Send divert request.
                iModel->SendCallDivertRequestL( setting,
                                                RMobilePhone::EServiceActionRegister,
                                                iVoiceMailboxDivert,
                                                ECFCmdActivate,
                                                (TGSCallDivertServices) iCurrentItem );
                }
            }
        );
    delete aContact;// Ownership is taken by this
    }


// --------------------------------------------------------------------------
// CGSCallDivertView::VPbkSingleContactOperationFailed
// --------------------------------------------------------------------------
//
void CGSCallDivertView::VPbkSingleContactOperationFailed(
    MVPbkContactOperationBase& /*aOperation*/,
    TInt /*aError*/)
    {
    if( iRetrieveOperation )
        {
        delete iRetrieveOperation;
        iRetrieveOperation = NULL;
        }

    }

// --------------------------------------------------------------------------
// CGSCallDivertView::OpenComplete
// --------------------------------------------------------------------------
//
void CGSCallDivertView::OpenComplete()
    {
    iStoresOpened = ETrue;
    }

// --------------------------------------------------------------------------
// CGSCallDivertView::StoreReady
// --------------------------------------------------------------------------
//
void CGSCallDivertView::StoreReady( MVPbkContactStore& /*aContactStore*/ )
    {
    // Do nothing
    }

// --------------------------------------------------------------------------
// CGSCallDivertView::StoreUnavailable
// --------------------------------------------------------------------------
//
void CGSCallDivertView::StoreUnavailable
        ( MVPbkContactStore& /*aContactStore*/, TInt /*aReason*/ )
    {
    // Do nothing
    }

// --------------------------------------------------------------------------
// CGSCallDivertView::HandleStoreEventL
// --------------------------------------------------------------------------
//
void CGSCallDivertView::HandleStoreEventL( MVPbkContactStore& /*aContactStore*/,
        TVPbkContactStoreEvent /*aStoreEvent*/ )
    {
    // Do nothing
    }



// ---------------------------------------------------------------------------
// CGSCallDivertView::CreateTimeListL
//
// Activates this view's popup list in order to change time-setting.
// ---------------------------------------------------------------------------
TInt CGSCallDivertView::CreateTimeListL()
    {
    CAknSinglePopupMenuStyleListBox* list =
        new ( ELeave ) CAknSinglePopupMenuStyleListBox;
    CleanupStack::PushL( list );

    CAknPopupList* popupList =
        CAknPopupList::NewL( list, R_AVKON_SOFTKEYS_OK_CANCEL__OK );
    CleanupStack::PushL( popupList );

    HBufC* title = StringLoader::LoadLC( R_TEXT_DELAY_HEADER );
    popupList->SetTitleL( *title );
    CleanupStack::PopAndDestroy( title );

    list->ConstructL( popupList,CEikListBox::ELeftDownInViewRect );
    list->CreateScrollBarFrameL( ETrue );
    list->ScrollBarFrame()->SetScrollBarVisibilityL(
        CEikScrollBarFrame::EOff,
        CEikScrollBarFrame::EAuto );

    CDesCArrayFlat* items;
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
        {
        items = new ( ELeave ) CDesCArrayFlat( KGSNrOfDelays + 4 );
        CleanupStack::PushL( items );
        CreateRestrictedCallDivertDelayTimeItemsL( *items );
        }
    else
        {
        items = new ( ELeave ) CDesCArrayFlat( KGSNrOfDelays );
        CleanupStack::PushL( items );
        CreateDelayTimeItemsL( *items );
        }
    CTextListBoxModel* model = list->Model();
    model->SetItemTextArray( items );
    model->SetOwnershipType( ELbmOwnsItemArray );
    CleanupStack::Pop(); //items
    list->HandleItemAdditionL();

    //set focus according to file read by phonesettings
    //set delay timer field value
    TInt currIndex = KErrNone;
    if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
        {
        TInt itemCount = items->Count();
        if (( iModel->DivertHandler()->GetTimerValueL() / KCFDelayStep ) > ( itemCount - 4))
            {
            // Within 60, 90, 120 range
            switch ( iModel->DivertHandler()->GetTimerValueL() )
                {
                case 60:
                    currIndex = itemCount - 3;
                    break;
                case 90:
                    currIndex = itemCount - 2;
                    break;
                case 120:
                    currIndex = itemCount - 1;
                    break;
                }
            }
        else
            {
            currIndex = iModel->DivertHandler()->GetTimerValueL() / KCFDelayStep;
            }
        }
    else
        {
        currIndex = ( iModel->DivertHandler()->GetTimerValueL() / KCFDelayStep ) - 1;
        }
    __GSLOGSTRING1( "[CGSCallDivertView::CreateTimeListL] currIndex: %d", currIndex );

    list->SetCurrentItemIndex( currIndex );
    //if possible show topmost item
    list->SetTopItemIndex(0);

    TInt keyPress = popupList->ExecuteLD();
    CleanupStack::Pop( popupList );
    if ( keyPress )
        {
        TInt index = list->CurrentItemIndex();
        __GSLOGSTRING1( "[CGSCallDivertView::CreateTimeListL] index: %d", index );

        if( FeatureManager::FeatureSupported( KFeatureIdRestrictedCallDivert ) )
            {
            TInt itemCount = items->Count();
            if ( index > ( itemCount - 4))
                {
                // Within 60, 90, 120 range
                if ( index == itemCount - 3)
                    {
                    iModel->DivertHandler()->SetTimerValueL( 60 );
                    }
                else if ( index == itemCount - 2 )
                    {
                    iModel->DivertHandler()->SetTimerValueL( 90 );
                    }
                else if ( index == itemCount - 1 )
                    {
                    iModel->DivertHandler()->SetTimerValueL( 120 );
                    }
                }
            else
                {
                // first entry is 0 seconds
                currIndex = iModel->DivertHandler()->SetTimerValueL( index * KCFDelayStep );
                }
            }
        else
            {
            //save to file the correct value calculated from index
            iModel->DivertHandler()->SetTimerValueL( ( index + 1 ) * KCFDelayStep );
            }
        }
    CleanupStack::PopAndDestroy( list );
    return keyPress;
    }

// --------------------------------------------------------------------------
// CGSCallDivertView::RemoveInvalidChars
// Remove invalid " ", "()" which were sync with PC suite. 
// --------------------------------------------------------------------------
//
void CGSCallDivertView::RemoveInvalidChars( TDes& aNumber )
  {
  TInt noOfInvalidchars = KCallDivertInvalidchars().Length();
  TInt location = KErrNone; 
  // delete the invalid chars of KCallDivertInvalidchars. 
  //aNumber changed to valid phone number if it contains invalid chars
  for ( TInt index = 0; index < noOfInvalidchars; index++ )
       {     
       while ( ETrue )
           {
           location = aNumber.Find( KCallDivertInvalidchars().Mid( index, 1 ) );   
           if ( location == KErrNotFound )
               {
               break;
               }
           aNumber.Delete( location, 1 ); //delete the invalid char, aNumber changed
           }
       }
  }
// End of File