phoneuis/easydialing/src/easydialingplugin.cpp
branchRCL_3
changeset 62 5266b1f337bd
child 81 c26cc2a7c548
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phoneuis/easydialing/src/easydialingplugin.cpp	Wed Sep 01 12:30:10 2010 +0100
@@ -0,0 +1,2359 @@
+/*
+* Copyright (c) 2010 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:  Easy dialing plugin.
+*
+*/
+
+// INCLUDE FILES
+
+#include "easydialingplugin.h"
+#include "easydialinglistbox.h"
+#include "easydialinglogger.h"
+#include "easydialingpanics.h"
+#include "easydialingcenreplistener.h"
+#include "easydialingcontactdatamanager.h"
+#include "easydialingutils.h"
+#include "easydialingcommands.hrh"
+#include <easydialingpluginresources.rsg>
+
+// AVKON and drawing header files
+#include <gdi.h>
+#include <aknlists.h>
+#include <AknUtils.h>
+#include <e32cmn.h>
+#include <bidivisual.h>
+
+#include <aknlayoutscalable_avkon.cdl.h>
+
+// Predictive search header files
+#include <CPsSettings.h>
+#include <CPsQuery.h>
+#include <CPsQueryItem.h>
+#include <CPsClientData.h>
+#include <CPsPattern.h>
+#include <CPsRequestHandler.h>
+
+// Virtual phonebook header files
+#include <VPbkContactStoreUris.h>
+#include <VPbkEng.rsg> // contains virtual phonebook data fields
+#include <phoneui.rsg> 
+
+// CCA Launcher header files.
+#include <ccafactory.h>
+#include <mccaparameter.h>
+#include <mccaconnection.h>
+#include <mccaconnectionext.h> 
+
+// Service provider settings api
+#include <spsettingsvoiputils.h>
+
+#include <StringLoader.h>
+
+// CCA contactor service.
+#include "edcontactorservice.h"
+
+// Open system trace
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "easydialingpluginTraces.h"
+#endif
+
+#include <phoneappcommands.hrh>
+#include <bautils.h>    // for BaflUtils
+
+// Transition effects
+#include <gfxtranseffect/gfxtranseffect.h>
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+const TInt KEDMaximumMatchingContactsCount = 100;
+const TInt KEasyDialingListBoxModelGranularity = 8;
+const TInt KEasyDialingMaximumMatchingParts = 10;
+const TInt KErrEasyDialingNoFirstNamePCSIndexing = -2000;
+const TInt KErrEasyDialingNoLastNamePCSIndexing = -2001;
+
+const TInt KEDFlushContactDataManagerLimit = 20;
+
+const TText KHighlightSeparatorChar = 0x1F;
+_LIT(KHighlightSeparatorCharAsLiteral,"\x1F");
+const TText KListFieldSeparatorChar = '\t';
+
+const TText KArabicAndSouthEastAsianRangeStart = 0x0600;
+const TText KArabicAndSouthEastAsianRangeEnd = 0x19FF;
+const TText KArabicPresentationFormsARangenStart = 0xFB50;
+const TText KArabicPresentationFormsARangeEnd = 0xFDFF;
+const TText KArabicPresentationFormsBRangenStart = 0xFE70;
+const TText KArabicPresentationFormsBRangeEnd = 0xFEFF;
+
+const TInt KMaxRunInfoArrayCount = 20;
+
+// Transition context_uid for dialer_list component effects
+#define KGfxContactListBoxUid TUid::Uid( 0x2000B47B )
+const TInt KGfxContactListBoxOpenEffect  = 3;
+const TInt KGfxContactListBoxCloseEffect = 4;
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+_LIT(KResourceFile, "\\resource\\easydialingpluginresources.rsc");
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+TInt CompareTPsMatchLocation( const TPsMatchLocation& a1, const TPsMatchLocation& a2 );
+
+void AppendStringWithMatchDataL(
+        TDes& aBuffer,
+        const TDesC& aText,
+        CPSRequestHandler* aPSHandler,
+        const CPsQuery* aPSQuery );
+
+TBool HighlightingSupportedForText( const TDesC& aText );
+
+inline TBool HighlightingSupportedForScript( TText aChar );
+
+TBool IsStrictlyBidirectional( const TDesC& aText );
+
+static HBufC* AllocWithoutHighlightSeparatorsLC( const TDesC& aDesc );
+
+static TBool IsItuTCharacter( TChar aChar );
+
+static TInt Find( const MVPbkContactLink* aLink, const RPointerArray<MVPbkContactLink>& aArray );
+
+template <class T>
+inline void CleanupResetAndDestroyPushL( T& aRef );
+
+
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin
+// The default c++ constructor
+// -----------------------------------------------------------------------------
+//
+CEasyDialingPlugin::CEasyDialingPlugin() 
+    : iActionToBeLaunched( ENoActionDefined )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// NewL
+// Create instance of concrete ECOM interface implementation.
+// -----------------------------------------------------------------------------
+//
+CEasyDialingPlugin* CEasyDialingPlugin::NewL()
+    {
+    OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_NEWL_LOAD_PLUGIN, "Loading plugin.." );
+    LOGSTRING("EasyDialingPlugin: Loading plugin..");
+
+    CEasyDialingPlugin* self = new (ELeave) CEasyDialingPlugin;
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_NEWL_LOAD_PLUGIN_OK, "Loading plugin completed succesfully" );
+    LOGSTRING("EasyDialingPlugin: Loading plugin completed succesfully");
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// ConstructL
+// Main construction handled here. Creates connection to the predictive search
+// engine and initialises all member data.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::ConstructL()
+    {
+    iLongTapped = EFalse;
+    // Create contact data manager.
+    iContactDataManager = CEasyDialingContactDataManager::NewL();
+    iContactDataManager->SetObserver( this );
+
+    // Find a handle to ca launcher extension MCCAConnectionExt.
+    // Easydialing has to use the extension API, because it needs function CloseAppL
+    // only found in extension.
+    // MCCAConnection extension has to be obtained through MCCAParameter extension,
+    // since MCCAConnection is not designed to be extensible API.
+    MCCAParameter* parameter = TCCAFactory::NewParameterL();
+    TAny* any = parameter->CcaParameterExtension( KMCCAConnectionExtUid );
+    
+    // Parameter can be deallocated since "any" containing pointer to contact launcher
+    // is not tied to parameter in any way.
+    parameter->Close();
+    
+    // Cast the pointer into contact launcher object. 
+    User::LeaveIfNull( any );
+    iContactLauncher = static_cast<MCCAConnectionExt*>( any );
+    
+    iCenrepListener = CEasyDialingCenrepListener::NewL( this );
+   
+    iContactorService = CEDContactorService::NewL( this );
+
+    // EasyDialing resource file is attempted to be read from the same directory where the
+    // executed binary is located
+    TFileName dllFileName;
+    Dll::FileName( dllFileName );
+    
+    TParse parse;
+    User::LeaveIfError( parse.Set(KResourceFile, &dllFileName, NULL) );
+    TFileName resourceFileName( parse.FullName() );
+
+    BaflUtils::NearestLanguageFile( iCoeEnv->FsSession(), resourceFileName );
+    iResourceFileOffset = iCoeEnv->AddResourceFileL( resourceFileName );
+  
+    SetComponentsToInheritVisibility( ETrue );
+    }
+
+// -----------------------------------------------------------------------------
+// ~CEasyDialingPlugin
+// The desctructor
+// -----------------------------------------------------------------------------
+//
+CEasyDialingPlugin::~CEasyDialingPlugin()
+    {
+    iObservers.Reset();
+    
+    delete iCenrepListener;
+    delete iContactDataManager;
+    delete iPredictiveSearchQuery;
+    iContactDataStores.ResetAndDestroy();
+
+    if ( iPredictiveContactSearchHandler )
+        {
+        iPredictiveContactSearchHandler->RemoveObserver(this);
+        }
+    delete iPredictiveContactSearchHandler;
+
+    delete iListBoxModel;
+    
+    if ( iContactListBox )
+        {
+        GfxTransEffect::Deregister( iContactListBox );
+        }
+    
+    delete iInfoLabelLine1;
+    delete iInfoLabelLine2;
+    delete iInfoLabelTextLine1;
+    delete iInfoLabelTextLine2;
+
+    delete iContactListBox;
+
+    if ( iContactLauncher )
+        {
+        iContactLauncher->Close();
+        }
+    
+    delete iContactorService;
+    
+    iCoeEnv->DeleteResourceFile( iResourceFileOffset );
+    
+    delete iInputBlocker;
+    
+    if ( iAsyncCallBack )
+        {
+        iAsyncCallBack->Cancel();
+        }
+    delete iAsyncCallBack;
+    
+    delete iContactToBeLaunched;
+    delete iContactToBeLaunchedName;
+    
+    OstTrace0( TRACE_NORMAL, CEASYDIALINGPLUGIN_UNLOAD_PLUGIN, "Plugin unloaded" );
+    LOGSTRING("EasyDialingPlugin: Plugin unloaded");
+    }
+
+
+// -----------------------------------------------------------------------------
+// InitializeL
+// Initialises easy dialing.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::InitializeL( CCoeControl& aParent )
+    {
+    SetContainerWindowL( aParent );
+    SetMopParent( &aParent );
+    
+    TCallBack asyncCallBack( AsyncCallBackToLaunchAction, this );
+    iAsyncCallBack = new ( ELeave ) CAsyncCallBack( asyncCallBack, 
+                                                    CActive::EPriorityStandard );
+
+    iContactListBox = new (ELeave) CEasyDialingListBox();
+    iListBoxModel = new(ELeave) CDesCArrayFlat( KEasyDialingListBoxModelGranularity );
+
+    iContactListBox->ConstructL( CEikListBox::EPaintedSelection
+            | CEikListBox::ENoFirstLetterMatching
+            | CEikListBox::EDisableItemSpecificMenu, 
+            iContactDataManager );
+    iContactListBox->SetListBoxObserver(this);
+
+    iContactListBox->SetMopParent(this);
+
+    CTextListBoxModel* model = iContactListBox->Model();
+    model->SetItemTextArray( iListBoxModel );
+    model->SetOwnershipType( ELbmDoesNotOwnItemArray );
+
+    iContactListBox->MakeVisible( EFalse );
+    
+    SetFocus( EFalse );
+    iContactListBox->ActivateL();
+    
+    _LIT( KEDNewLine, "\n" );
+    HBufC* infoLabelText = StringLoader::LoadLC( R_QTN_EASYDIAL_ENTER_NUMBER, iCoeEnv );
+    TInt newLine = infoLabelText->Find( KEDNewLine );
+    if ( newLine == KErrNotFound )
+        {
+        iInfoLabelTextLine1 = infoLabelText;
+        CleanupStack::Pop( infoLabelText );
+        iInfoLabelTextLine2 = HBufC::NewL(0);
+        }
+    else
+        {
+        iInfoLabelTextLine1 = infoLabelText->Left( newLine ).AllocL();
+        iInfoLabelTextLine2 = infoLabelText->Mid( newLine + 1 ).AllocL();
+        CleanupStack::PopAndDestroy( infoLabelText );
+        }
+            
+    iInfoLabelLine1 = new( ELeave ) CEikLabel;
+    iInfoLabelLine1->SetContainerWindowL( *this );
+    iInfoLabelLine1->SetParent( this );
+    iInfoLabelLine1->SetMopParent( this ); 
+    iInfoLabelLine1->SetLabelAlignment( ELayoutAlignCenter );
+    iInfoLabelLine1->SetTextL( *iInfoLabelTextLine1 );
+    iInfoLabelLine1->ActivateL();
+
+    iInfoLabelLine2 = new( ELeave ) CEikLabel;
+    iInfoLabelLine2->SetContainerWindowL( *this );
+    iInfoLabelLine2->SetParent( this );
+    iInfoLabelLine2->SetMopParent( this ); 
+    iInfoLabelLine2->SetLabelAlignment( ELayoutAlignCenter );
+    iInfoLabelLine2->SetTextL( *iInfoLabelTextLine2 );
+    iInfoLabelLine2->ActivateL();
+
+    SetInfoLabelColourL();
+    
+    GfxTransEffect::Register( iContactListBox, 
+                              KGfxContactListBoxUid, EFalse );
+    
+    iCoeEnv->AddForegroundObserverL( *this );
+    
+    // Do delayed initialization of PCS. PCS constructions takes a long time.
+    // On the other hand, easy dialing initialization is done in phone application
+    // constructor, so it contributes the whole system boot time. These are good 
+    // reasons not to construct PCS in easy dialing constructor, but do it later as
+    // an asynchronous operation.
+    AsyncActionLaunchL( EInitializePcs );
+    }
+
+
+// -----------------------------------------------------------------------------
+// Reset
+// Resets easydialing plugin.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::Reset()
+    {
+    // PCS searches completing after the Reset() call must be discarded
+    iDiscardCompletingSearches = ETrue;
+    
+    iNewSearchNeeded = EFalse;
+    iSearchString.Zero();
+    iListBoxModel->Reset();
+    iNumberOfNames = 0;
+    iContactListBox->MakeVisible( EFalse );
+    iContactDataManager->Reset();
+    if ( IsFocused() )
+        {
+        SetFocus( EFalse );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// InitPredictiveContactSearchL
+// Initialises predictive contact search.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::InitPredictiveContactSearchL()
+    {
+    iPredictiveContactSearchHandler = CPSRequestHandler::NewL();
+    iPredictiveContactSearchHandler->AddObserverL(this);
+
+    // Check which relevant contact fields are indexed in PCS search.
+    iFirstNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_FIRSTNAME );
+    iLastNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_LASTNAME );
+    iCompanyNamePCSIndex = FindContactFieldPCSIndexL( R_VPBK_FIELD_TYPE_COMPANYNAME );
+
+    // If first name and last name are not indexed in PCS, easy dialing plugin
+    // can not function reasonably. The function leaves, which in turn causes
+    // the plugin not to be initialized.
+    // Company name not being indexed is not as severe case, and does not cause a leave.
+    // Fields used in PCS indexing are configured in cenrep 2000B5C6.
+    if ( iFirstNamePCSIndex == KErrNotFound )
+        {
+        OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_INITPREDICTIVECONTACTSEARCHL_ERROR_NO_FIRST_NAME, "ERROR, PCS does not support first name indexing!" );
+        LOGSTRING("EasyDialingPlugin: PCS does not support first name indexing => Leave");
+        User::Leave( KErrEasyDialingNoFirstNamePCSIndexing );
+        }
+    if ( iLastNamePCSIndex == KErrNotFound )
+        {
+        OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_INITPREDICTIVECONTACTSEARCHL_ERROR_NO_LAST_NAME, "ERROR, PCS does not support last name indexing!" );
+        LOGSTRING("EasyDialingPlugin: PCS does not support last name indexing => Leave");
+        User::Leave( KErrEasyDialingNoLastNamePCSIndexing );
+        }
+
+    SetupPcsSettingsL();
+
+    iPredictiveSearchQuery = CPsQuery::NewL();
+    }
+
+// -----------------------------------------------------------------------------
+// SetupPcsSettingsL
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetupPcsSettingsL()
+    {
+    // Get current store configuration from Phonebook settings
+    iContactDataStores.ResetAndDestroy();
+    iContactDataManager->GetCurrentStoreUrisL( iContactDataStores );
+    
+    // Put the searched contact fields into array.
+    RArray<TInt> contact_fields;
+    CleanupClosePushL(contact_fields);
+
+    // First name, last name and company name (if supported) are used in PCS search.
+    contact_fields.Append( R_VPBK_FIELD_TYPE_FIRSTNAME );
+    contact_fields.Append( R_VPBK_FIELD_TYPE_LASTNAME );
+    contact_fields.Append( R_VPBK_FIELD_TYPE_COMPANYNAME );
+
+    // Create and fill PS settings object.
+    CPsSettings* ps_settings = CPsSettings::NewL();
+    CleanupStack::PushL( ps_settings );
+
+    ps_settings->SetSearchUrisL( iContactDataStores );
+    ps_settings->SetMaxResults( KEDMaximumMatchingContactsCount );
+    ps_settings->SetSortType( EAlphabetical );
+    ps_settings->SetDisplayFieldsL( contact_fields );
+
+    // Set the PCS settings.
+    iPredictiveContactSearchHandler->SetSearchSettingsL( *ps_settings );
+
+    CleanupStack::PopAndDestroy( ps_settings );
+    CleanupStack::PopAndDestroy( &contact_fields );
+
+    // Set the sort order. This must happen after the contact store settings
+    // are up-to-date.
+    SetSortOrderL( iContactDataManager->NameOrder() );
+    }
+
+// -----------------------------------------------------------------------------
+// SetSortOrderL
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetSortOrderL( CEasyDialingContactDataManager::TNameOrder aNameOrder )
+    {
+    RArray<TInt> fields;
+    CleanupClosePushL( fields );
+    if ( aNameOrder == CEasyDialingContactDataManager::EFirstnameLastname )
+        {
+        fields.AppendL( R_VPBK_FIELD_TYPE_FIRSTNAME );
+        fields.AppendL( R_VPBK_FIELD_TYPE_LASTNAME );
+        }
+    else
+        {
+        fields.AppendL( R_VPBK_FIELD_TYPE_LASTNAME );
+        fields.AppendL( R_VPBK_FIELD_TYPE_FIRSTNAME );
+        }
+    fields.AppendL( R_VPBK_FIELD_TYPE_COMPANYNAME );
+    
+    // Set the same order for each contact store. PCS automatically ignores
+    // fields not supported by the given store.
+    for ( TInt i = 0 ; i < iContactDataStores.Count() ; ++i )
+        {
+        iPredictiveContactSearchHandler->ChangeSortOrderL( *iContactDataStores[i], fields );
+        }
+    CleanupStack::PopAndDestroy( &fields );
+    }
+
+// -----------------------------------------------------------------------------
+// OfferKeyEventL
+// Check the received keypad event and performs user
+// actions related to it.
+// -----------------------------------------------------------------------------
+//
+TKeyResponse CEasyDialingPlugin::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
+    {
+    TKeyResponse keyResponse = EKeyWasNotConsumed;
+
+    if ( aType != EEventKey )
+        {
+        return keyResponse;
+        }
+
+    TInt keyCode = aKeyEvent.iCode;
+    
+    // Swap right and left key codes in mirrored layout.
+    if ( AknLayoutUtils::LayoutMirrored() ) 
+        {
+        if ( keyCode == EKeyRightArrow ) keyCode = EKeyLeftArrow;
+        else if ( keyCode == EKeyLeftArrow ) keyCode = EKeyRightArrow;
+        }
+    
+
+    if ( IsFocused() )
+        {
+        if ( keyCode == EKeyUpArrow )
+            {
+            // if the focus is on the top-most item
+            if ( iContactListBox->CurrentItemIndex() == 0)
+                {
+                // then focus jumps off the component.
+                SetFocus( EFalse );
+                DrawDeferred();
+                keyResponse = EKeyWasConsumed;
+                }
+            else
+                {
+                keyResponse = iContactListBox->OfferKeyEventL( aKeyEvent, aType );
+                }
+            }
+        else if ( keyCode == EKeyDownArrow )
+            {
+            // if the focus is on the bottom-most item
+            if ( iContactListBox->CurrentItemIndex() == (iNumberOfNames - 1) )
+                {
+                // then focus jumps off the component.
+                SetFocus( EFalse );
+                DrawDeferred();
+                keyResponse = EKeyWasConsumed;
+                }
+            else
+                {
+                keyResponse = iContactListBox->OfferKeyEventL( aKeyEvent, aType );
+                }
+            }
+
+        else if ( keyCode == EKeyRightArrow )
+            {
+            iRememberFocus = ETrue;
+            AsyncActionLaunchL( ELaunchCurrentContact );
+            keyResponse = EKeyWasConsumed;
+            }
+
+        else if ( keyCode == EKeyLeftArrow )
+            {
+            // then focus jumps off the component.
+            SetFocus( EFalse );
+            DrawDeferred();
+            keyResponse = EKeyWasConsumed;
+            }
+
+        else
+            {
+            // then focus jumps off the component.
+            SetFocus( EFalse );
+            
+            // FEP hasn't had chance to handle this key event as focus was not in the editor field.
+            // Give that chance now by consuming original event and simulating a new one.
+            // The simulation must be asynchronous because FEP focusing state is updated
+            // with high priority active object.
+            // As an exception, dialer simulated keys are given directly to editor. They are
+            // not handled by FEP anyway, and asynchronous handling would be problematic for
+            // the * key multitapping logic of Phone.
+            TBool simulatedByDialer = (aKeyEvent.iModifiers&EModifierNumLock) &&
+                                      (aKeyEvent.iModifiers&EModifierKeypad);
+            if ( !simulatedByDialer )
+                {
+                keyResponse = EKeyWasConsumed;
+                AsyncSimulateKeyEvent( aKeyEvent );
+                }
+            }
+        }
+
+    else if ( iNumberOfNames > 0 ) // not in focus but there are contacts to show
+        {
+        if ( keyCode == EKeyUpArrow || keyCode == EKeyDownArrow )
+            {
+            SetFocus( ETrue );
+            keyResponse = iContactListBox->SetFocusedWithKeyEventL( aKeyEvent, aType );
+            }
+        }
+    return keyResponse;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CountComponentControls
+//
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::CountComponentControls() const
+    {
+    return iNumberOfNames > 0 ? 3 : 2;
+    }
+
+
+// -----------------------------------------------------------------------------
+// ComponentControl
+//
+// -----------------------------------------------------------------------------
+//
+CCoeControl* CEasyDialingPlugin::ComponentControl( TInt aIndex ) const
+    {
+    switch ( aIndex )
+        {
+        case 0:
+            return iInfoLabelLine1;
+        case 1:
+            return iInfoLabelLine2;
+        case 2:
+            return iContactListBox;
+        default:
+            return NULL;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// MakeVisible
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::MakeVisible( TBool aVisible )
+    {
+    if ( aVisible != IsVisible() )
+        {
+        CCoeControl::MakeVisible( aVisible );
+        
+        if ( !aVisible && IsFocused() )
+            {
+            SetFocus( EFalse );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HandleResourceChange
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandleResourceChange( TInt /*aType*/ )
+    {
+    TRAP_IGNORE( SetInfoLabelColourL() );
+    }
+
+// -----------------------------------------------------------------------------
+// SizeChanged
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SizeChanged()
+    {
+    TRect rect = Rect();
+    // convert rect to absolute coordinates
+    rect.SetRect( PositionRelativeToScreen(), rect.Size() );
+    
+    iContactListBox->SetMaxRect( rect );
+    iContactListBox->SetRectToNumberOfItems( iNumberOfNames );
+    
+    TInt itemToMakeVisible = iContactListBox->CurrentItemIndex();  
+    if ( itemToMakeVisible == KErrNotFound && iNumberOfNames )
+        {
+        // if no current item is set, make sure that the list is then 
+        // scrolled to the bottom.
+        itemToMakeVisible = iNumberOfNames - 1;
+        } 
+    iContactListBox->ScrollToMakeItemVisible( itemToMakeVisible );
+
+    // get info label locations and fonts from layout
+    TRect baseRect = Rect();
+    TAknTextComponentLayout labelLayoutLine1 = 
+        AknLayoutScalable_Avkon::main_pane_empty_t1( 0 );
+    TAknTextComponentLayout labelLayoutLine2 = 
+        AknLayoutScalable_Avkon::main_pane_empty_t2( 0 );
+    AknLayoutUtils::LayoutLabel( iInfoLabelLine1, baseRect, labelLayoutLine1 );
+    AknLayoutUtils::LayoutLabel( iInfoLabelLine2, baseRect, labelLayoutLine2 );
+    
+    // the layouts used place the text too low, so center the labels vertically
+    TInt labelHeight = iInfoLabelLine2->Rect().iBr.iY - iInfoLabelLine1->Rect().iTl.iY;
+    TInt centeredTop = ( baseRect.Height() - labelHeight ) / 2;
+    TInt offset = centeredTop - iInfoLabelLine1->Rect().iTl.iY;
+    iInfoLabelLine1->SetPosition( TPoint( iInfoLabelLine1->Rect().iTl.iX,
+                                          iInfoLabelLine1->Rect().iTl.iY + offset ) );
+    iInfoLabelLine2->SetPosition( TPoint( iInfoLabelLine2->Rect().iTl.iX,
+                                          iInfoLabelLine2->Rect().iTl.iY + offset ) );
+    
+    TRAP_IGNORE( SetInfoLabelColourL() );
+    }
+
+
+// -----------------------------------------------------------------------------
+// FocusChanged
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::FocusChanged( TDrawNow aDrawNow )
+    {
+    iContactListBox->SetFocus( IsFocused() );
+    if ( !IsFocused() )
+        {
+        // To be on the safe side, cancel async callback and reset input block.
+        CancelActionLaunchAndInputBlock();
+        iContactListBox->View()->ItemDrawer()->ClearFlags( CListItemDrawer::ESingleClickDisabledHighlight );
+        }
+    CCoeControl::FocusChanged( aDrawNow );
+    InformObservers( MDialingExtensionObserver::EFocusChanged );
+    }
+
+
+// -----------------------------------------------------------------------------
+// SetInputL
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetInputL( const TDesC& aSearchString )
+    {
+    if ( !IsEnabled() )
+        {
+        return;
+        }
+    OstTraceExt1( TRACE_NORMAL, CEASYDIALINGPLUGIN_SET_INPUT, "SetInput: '%S' ", aSearchString );
+    LOGSTRING1("EasyDialingPlugin: SetInput: '%S'", &aSearchString );
+    
+    // Earlier here was a test if the search string is the same as the one used in previous search.
+    // If it was, no search was done but function returned immediately.
+    // This has now been removed. It is possible that contacts have changed, and a new search
+    // may be needed even if the search string is the same. 
+    
+    // Check if search string is just empty space or 0-length. Decision was made that no
+    // matches are shown if search string is just space (would show all contacts)
+    // even if somebody might have unnamed contacts. Should be quite rare.
+    // It's assumed later on in the code that string is not just empty space.
+    TLex searchString( aSearchString );
+    searchString.SkipSpace();
+    if ( searchString.Eos() ) // the end of the string reached after skipping empty space
+        {
+        // It's assumed here that if we get here due to switching to call
+        // handling etc, then dialer and thus ed is already set invisible
+        // and effect will not be shown as listbox is already invisible.
+        // However if user empties number entry, then it's feasible to show
+        // effect.
+        HideContactListBoxWithEffect();
+        SetInfoLabelVisibleL( ETrue );
+        Reset();
+        }
+    else // proper search string
+        {
+        SetInfoLabelVisibleL( EFalse );
+        iSearchString.Copy( aSearchString.Left( iSearchString.MaxLength() ) );
+        LaunchSearchL();
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// MatchingContactCount
+//
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::MatchingContactCount()
+    {
+    return iNumberOfNames;
+    }
+
+
+// -----------------------------------------------------------------------------
+// EasyDialingSettingsChanged
+// From MEasyDialingCenrepListenerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::EasyDialingSettingsChanged( TInt aValue )
+    {
+    if ( aValue == 0 )
+        {
+        Reset();
+        InformObservers( MDialingExtensionObserver::EEasyDialingDisabled );
+        TRAP_IGNORE( SetInfoLabelVisibleL( EFalse ) );
+        }
+    else if ( aValue == 1 )
+        {
+        InformObservers( MDialingExtensionObserver::EEasyDialingEnabled );
+        if ( iSearchString.Length() == 0 )
+            {
+            TRAP_IGNORE( SetInfoLabelVisibleL( ETrue ) );
+            }
+        }
+    MakeVisible( aValue );
+    }
+
+// -----------------------------------------------------------------------------
+// EasyDialingContactThumbnailsSettingsChanged
+// From MEasyDialingCenrepListenerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::EasyDialingContactThumbnailsSettingsChanged( TInt aThumbnailSettingValue )
+    {
+    iContactDataManager->SetContactThumbnailSetting( aThumbnailSettingValue );
+    iContactDataManager->Reload();
+    DrawDeferred();
+    }
+
+// -----------------------------------------------------------------------------
+// AllContactDataLoaded
+// From MContactDataManagerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::AllContactDataLoaded()
+    {
+    iContactListBox->DrawDeferred();
+    }
+
+// -----------------------------------------------------------------------------
+// NameOrderChanged
+// From MContactDataManagerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::NameOrderChanged()
+    {
+    if ( iPredictiveContactSearchHandler )
+        {
+        TRAP_IGNORE( SetSortOrderL( iContactDataManager->NameOrder() ) );
+        // Refresh current results if needed
+        TRAP_IGNORE( DoHandleContactsChangedL() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// FavouritesChanged
+// From MContactDataManagerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::FavouritesChanged()
+    {
+    TRAP_IGNORE( DoHandleContactsChangedL() );
+    }
+
+// -----------------------------------------------------------------------------
+// StoreConfigurationChanged
+// From MContactDataManagerObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::StoreConfigurationChanged()
+    {
+    TRAP_IGNORE( 
+        // Reconfigure PCS to update its store settings
+        SetupPcsSettingsL();
+        // Contacts available have changed and a new search is needed if we have
+        // previous results shown.
+        DoHandleContactsChangedL() 
+        );
+    }
+
+// -----------------------------------------------------------------------------
+// InformContactorEvent
+// From MEDContactorObserver
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::InformContactorEvent( MEDContactorObserver::TEvent aEvent )
+    {
+    // This callback function simply propagates the events to its own listener.
+    switch ( aEvent )
+        {
+        case MEDContactorObserver::ECommunicationStarted:
+            InformObservers( MDialingExtensionObserver::ECommunicationStarted );
+            break;
+        case MEDContactorObserver::ECommunicationCancelled:
+            InformObservers( MDialingExtensionObserver::ECommunicationCancelled );
+            break;
+        default:
+            break;
+        }
+    
+    // Reset focus unless it is flagged to be remembered.
+    if ( !iRememberFocus )
+        {
+        SetFocus( EFalse );
+        DrawDeferred();
+        }
+    
+    iRememberFocus = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// Draw
+// The actual UI drawing function. Draws the easy dialing popup bubble on the
+// idle screen.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::Draw( const TRect& /* aRect */ ) const
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// LaunchSearchL
+// Initiates predictive contact search.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::LaunchSearchL()
+    {
+    if ( iSearchString.Length() == 0 || !iPredictiveContactSearchHandler )
+        {
+        return;
+        }
+    
+    iDiscardCompletingSearches = EFalse;
+    iNewSearchNeeded = EFalse;
+    
+    iPredictiveSearchQuery->Reset();
+
+    for ( TInt i = 0; i < iSearchString.Length(); i++ )
+        {
+         // Add a query item
+        CPsQueryItem* item = CPsQueryItem::NewL();
+        CleanupStack::PushL(item);
+
+        item->SetCharacter( iSearchString[i] );
+        
+        // The PCS mode used with character is based on character itself,
+        // not to the keyboard it is made with. While this is not strictly
+        // identical to checking the used keyboard, this behaves identically
+        // in most of the normal cases, and makes the logic simpler.
+        // In case of hybrid mode keyboard, use always predictive default 
+        // keyboard.
+        if ( iKeyboardMode == EDefaultKeyboard && 
+             IsItuTCharacter( iSearchString[i] ) )
+            {
+            item->SetMode( EPredictiveItuT );
+            }
+        else 
+            {
+            item->SetMode( EPredictiveDefaultKeyboard );
+            }
+        
+        iPredictiveSearchQuery->AppendL(*item);
+
+        // Previous CPsQuery::AppendL takes the ownership of item.
+        // Do not delete item.
+        CleanupStack::Pop(item);
+        }
+
+    // Issue the search. SearchL is asynchronous function => returns immediately.
+    iPredictiveContactSearchHandler->SearchL(*iPredictiveSearchQuery);
+    }
+
+
+// -----------------------------------------------------------------------------
+// HandlePsResultsUpdate from MPsResultsObserver
+// Called after predictive search has been completed.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandlePsResultsUpdate( RPointerArray<CPsClientData>& aResults, RPointerArray<CPsPattern>& aSeqs )
+    {
+    if ( !IsEnabled() )
+        {
+        // Easydialing is off. We should arrive here only if user turned it off while a search was happening.
+        Reset();
+        return;
+        }
+    TRAPD( leaveError, HandlePsResultsUpdateL( aResults, aSeqs ) );
+
+    if ( leaveError )
+        {
+        OstTrace1( TRACE_ERROR, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATE, "HandlePsResultsUpdate failed: %d", leaveError );
+        LOGSTRING1("EasyDialingPlugin: HandlePsResultsUpdate failed: %d", leaveError );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// HandlePsError from MPsResultsObserver
+// Called when search error happens.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandlePsError( TInt aErrorCode )
+    {
+    OstTrace1( TRACE_ERROR, CEASYDIALINGPLUGIN_HANDLEPSERROR, "PCS Error: %d", aErrorCode );
+    LOGSTRING1("EasyDialingPlugin: PCS Error: %d", aErrorCode );
+    }
+
+// -----------------------------------------------------------------------------
+// CachingStatus from MPsResultsObserver
+// Called to update caching status.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::CachingStatus( TCachingStatus& aStatus, TInt& aError )
+    {
+    OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_CACHINGSTATUS, "PCS CachingStatus: %d, error: %d", ( TUint )( aStatus ), aError );
+    
+    switch ( aStatus )
+        {
+        case ECacheUpdateContactRemoved:
+        case ECacheUpdateContactModified:
+        case ECacheUpdateContactAdded:
+            TRAP_IGNORE( DoHandleContactsChangedL() );
+            break;
+        default:
+            break;
+        }
+    
+    LOGSTRING2("EasyDialingPlugin: PCS CachingStatus: %d, error: %d", aStatus, aError );
+    }
+
+
+// -----------------------------------------------------------------------------
+// FindContactFieldPCSIndex
+// Searches the index that stores the given contact field.
+// To see possible contact field numbering, see file "vpbkeng.rsg".
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::FindContactFieldPCSIndexL( TInt aIndex )
+    {
+    RArray<TInt> fieldOrder;
+    CleanupClosePushL( fieldOrder );
+
+    // PCS uses the same data plugin for all the Phonebook databases
+    // (i.e. phone contacts, SIM contacts, SDN contacts), and there can be only
+    // one data order per plugin. Thus, data order for all databases supported
+    // by us is the same, and it's enough to ask data order just for the default CDB.
+    const TDesC& defaultCdb = VPbkContactStoreUris::DefaultCntDbUri();
+
+    iPredictiveContactSearchHandler->GetDataOrderL( defaultCdb, fieldOrder );
+    TInt pcsIndex = fieldOrder.Find( aIndex );
+
+    CleanupStack::PopAndDestroy( &fieldOrder );
+    return pcsIndex;
+    }
+
+
+// -----------------------------------------------------------------------------
+// HandlePsResultsUpdateL
+// This function does the actual callback fork, and must be trapped inside
+// HandlePsResultsUpdateL.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandlePsResultsUpdateL( RPointerArray<CPsClientData>& aResults, RPointerArray<CPsPattern>& /*aSeqs*/ )
+    {
+    // If iDiscardCompletingSearches is ETrue, don't show search results but just return.
+    // If easydialing has been reset with reset function, no searches completed after that
+    // can be shown.
+    // This is done like this because there seems not to be a feasible way of cancelling all 
+    // PCS search request in PCS API. CancelRequest does not work here.
+    if ( iDiscardCompletingSearches )
+        {
+        return;
+        }
+    
+    iListBoxModel->Reset();
+    iContactListBox->HandleItemRemovalL();
+
+    TInt numberOfPCSMatches( aResults.Count() );
+    
+    // Resetting the contactdatamanager causes the thumbnails to flicker a bit, because
+    // we need to load the thumbnails again. But if there are lots of search results, or
+    // lots of loaded thumbnails in the manager, matching the search results to the
+    // thumbnail manager contents may take too much time. If there are lots of results,
+    // it is likely that the contents of the listbox change anyway, so the flickering
+    // doesn't matter too much. This also limits the memory usage of the manager.
+    //   But if there are fewer search results, it is worth trying to match them
+    // with the contents of thumbnail manager.
+    
+    TBool matchThumbnails(ETrue);
+    if ( numberOfPCSMatches > KEDFlushContactDataManagerLimit )
+        {
+        iContactDataManager->Reset();
+        matchThumbnails = EFalse;
+        }
+
+    OstTrace1( TRACE_NORMAL, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATEL_MATCHES, "Matching results from PCS: %d", numberOfPCSMatches );
+    LOGSTRING1("EasyDialingPlugin: Matching results from PCS: %d", numberOfPCSMatches );
+
+    // retrieve the name order before adding
+    CEasyDialingContactDataManager::TNameOrder nameOrder = iContactDataManager->NameOrder();
+
+    RPointerArray<MVPbkContactLink> favsFoundByPcs;
+    CleanupResetAndDestroyPushL( favsFoundByPcs );
+    
+    // Update the model
+    // ----------------
+    for ( TInt i = 0; i < numberOfPCSMatches; i++ )
+        {
+        TInt indexFromEnd = numberOfPCSMatches - i - 1;
+
+        MVPbkContactLink* link = iPredictiveContactSearchHandler->ConvertToVpbkLinkLC(
+                *(aResults[indexFromEnd]), iContactDataManager->ContactManager() );
+        if ( !iContactDataManager->IsFavL( link ) )
+            {
+            // handle favourites separately, in another loop
+            HBufC* contactString = CreateContactStringLC( aResults[ indexFromEnd ], nameOrder );
+            CreateListBoxContactStringL( *contactString, link, matchThumbnails, EFalse );
+            CleanupStack::PopAndDestroy( contactString );
+            CleanupStack::PopAndDestroy( link );
+            }
+        else
+            {
+            // favourites are handled later
+            favsFoundByPcs.AppendL( link );
+            CleanupStack::Pop( link );
+            }
+        
+        OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_HANDLEPSRESULTSUPDATEL_SHOW_MATCH, "Contact #%d: '%S'", i+1, iContactStringCreationBuffer );
+        LOGSTRING2( "EasyDialingPlugin: Contact #%d: '%S'", i+1, &iContactStringCreationBuffer );
+        }
+
+    // Search synchronously through all the favourite contacts to ensure
+    // that all favourite matches are added to bottom even when number of mathces
+    // exceeds the maximum number set to PCS
+    TInt numberOfFavs( iContactDataManager->NumberOfFavsL() );
+    TBuf<KBufferMaxLen> results;
+    for ( TInt i = numberOfFavs - 1; i >= 0; i-- )
+        {
+        HBufC* favContactString = iContactDataManager->FavContactStringLC( i, nameOrder );
+        MVPbkContactLink* link = iContactDataManager->FavLinkLC( i );
+        
+        // Check if this fav contact was returned in aResults.
+        // It's at least theoretically possible that all matches in aResults
+        // are not matched when using LookupMatchL. PCS has completely separate logics
+        // for functions SearchL and LookupMatchL and especially with Chinese variant
+        // they may return different results.
+        TBool found = ( Find( link, favsFoundByPcs ) != KErrNotFound );
+        
+        // If this fav contact was not in aResults, then use LookupMatchL
+        // to check if this contact is still a match and was excluded from aResults
+        // because maximum number of results was exceeded.
+        if ( !found )
+            {
+            results = KNullDesC;
+            iPredictiveContactSearchHandler->LookupMatchL(
+                    *iPredictiveSearchQuery, *favContactString, results );
+            found = ( results.Length() > 0 );
+            }
+
+        if ( found )
+            {
+            // matches, add this fav to listbox.
+            CreateListBoxContactStringL( *favContactString, link, matchThumbnails, ETrue );
+            }
+
+        CleanupStack::PopAndDestroy(); // link
+        CleanupStack::PopAndDestroy( favContactString );
+        }
+    
+    CleanupStack::PopAndDestroy( &favsFoundByPcs ); // ResetAndDestroy
+    
+    // Update the view
+    // ---------------
+    iNumberOfNames = iListBoxModel->Count();
+    if ( iNumberOfNames )
+        {
+        TInt oldRectHeight = iContactListBox->Rect().Height();
+        
+        iContactListBox->SetRectToNumberOfItems( iNumberOfNames );
+        
+        // If the window is resized (->position changes too) while it's visible, 
+        // it has to be redrawn immediately or otherwise listbox will flash
+        // in a wrong place on the screen during execution of this method
+        // HandlePsResultsUpdateL. In the worst case it'll flash on top of
+        // dialer's numeric keypad when listbox is made smaller.
+        if ( oldRectHeight != iContactListBox->Rect().Height() )
+            {
+            iContactListBox->DrawNow();
+            }
+
+        iContactListBox->HandleItemAdditionL();
+        
+        // Scroll the list to bottom
+        iContactListBox->ScrollToMakeItemVisible( iNumberOfNames-1 );
+
+        ShowContactListBoxWithEffect();
+        iContactListBox->View()->ItemDrawer()->ClearFlags( CListItemDrawer::ESingleClickDisabledHighlight );
+        static_cast<CEasyDialingListBoxView*>( iContactListBox->View() )->SetCurrentItemIndexToNone();
+        }
+    else
+        {  
+        HideContactListBoxWithEffect();
+        }
+
+    if ( IsFocused() )
+        {
+        SetFocus( EFalse );
+        }
+
+    DrawDeferred();
+
+    InformObservers( MDialingExtensionObserver::ESearchComplete );
+    }
+
+
+// -----------------------------------------------------------------------------
+// void CCASimpleNotifyL()
+// Implements MCCAObserver notification interface.
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::CCASimpleNotifyL( TNotifyType aType, TInt aReason )
+    {
+    OstTraceExt2( TRACE_NORMAL, CEASYDIALINGPLUGIN_CCASIMPLENOTIFYL, "CCASimpleNotifyL: type: %d, reason: %d", ( TUint )( aType ), aReason );
+    LOGSTRING2("EasyDialingPlugin: CCASimpleNotifyL: type: %d, reason: %d", (TInt)aType, aReason );
+
+    iContactLauncherActive = EFalse;
+
+    CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() );
+    appUi->HandleCommandL( EPhoneCmdBlockingDialogClosed );
+
+    // Give up focus, if iRememberFocus flag is not set.
+    if ( !iRememberFocus )
+        {
+        SetFocus( EFalse );
+        DrawDeferred();
+        }    
+    iRememberFocus = EFalse;
+
+    // Inform observers.
+    InformObservers( MDialingExtensionObserver::ECCALauncherExit );
+    }
+
+
+// -----------------------------------------------------------------------------
+// void LaunchCurrentContactL()
+// Implements MCCAObserver notification interface.
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::LaunchCurrentContactL()
+    {
+    __ASSERT_DEBUG( iNumberOfNames > 0, EasyDialingPanic( EEasyDialingPanicNoResults ) );
+    __ASSERT_DEBUG( iContactToBeLaunched, EasyDialingPanic( EEasyDialingPanicNoContactSelected ) );
+
+    if (( iContactLauncherActive ) || ( iNumberOfNames == 0 ) || ( !iContactListBox ) || ( !iContactToBeLaunched ))
+        {
+        OstTrace0( TRACE_ERROR, CEASYDIALINGPLUGIN_LAUNCHCURRENTCONTACTL_ERROR, "LaunchCurrentContactL: Parameter error" );
+        LOGSTRING("EasyDialingPlugin: LaunchCurrentContactL - Parameter error");
+        return;
+        }
+
+    MCCAParameter* launchParameters = TCCAFactory::NewParameterL();
+    CleanupClosePushL( *launchParameters );
+
+    // ESoftExit flag causes that ca launcher will not close the 
+    // client application in any circumstance. 
+    // Application hosting easydialing is telephone application.
+    // It must never be closed, so we must use this flag.
+    launchParameters->SetConnectionFlag(MCCAParameter::ESoftExit);
+    
+    launchParameters->SetContactDataFlag(MCCAParameter::EContactLink);
+
+    // Expand contact link into 16-bit descriptor because cca launcher api expects this. 
+    HBufC16* contact16 = HBufC16::NewLC( iContactToBeLaunched->Length() );
+    contact16->Des().Copy( *iContactToBeLaunched );
+
+    launchParameters->SetContactDataL( *contact16 );
+
+    CleanupStack::PopAndDestroy( contact16 );
+
+    OstTraceExt1( TRACE_NORMAL, CEASYDIALINGPLUGIN_LAUNCHCURRENTCONTACTL_LAUNCH_CCA, "Launch CL for contact: '%S'", *iContactToBeLaunchedName );
+    LOGSTRING1("EasyDialingPlugin: Launch CL for contact: '%S'", iContactToBeLaunchedName );
+
+    delete iContactToBeLaunched;
+    iContactToBeLaunched = NULL;
+    delete iContactToBeLaunchedName;
+    iContactToBeLaunchedName = NULL;    
+    
+    iContactLauncher->LaunchAppL( *launchParameters, this );
+
+    // Ownership of parameter transferred to CCA launcher => pop but do not destroy.
+    CleanupStack::Pop( launchParameters );
+
+    if ( !IsVisible() )
+        {
+        // MCCAConnection::LaunchAppL uses CActiveSchedulerWait to hide asynchronous
+        // opening of CCA launcher. It is possible that during opening of CCA launcher
+        // phone has moved to in-call view (at least in case of an incoming call).
+        // In that case we need to close CCA launcher again.
+        iContactLauncher->CloseAppL();
+        }
+    else
+        {
+        iContactLauncherActive = ETrue;
+        CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() );
+        appUi->HandleCommandL( EPhoneCmdBlockingDialogLaunched );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CreateListBoxContactStringL
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::CreateListBoxContactStringL(
+        const TDesC& aContactString,
+        MVPbkContactLink *aLink,
+        TBool aMatchThumbnails,
+        TBool aFav )
+    {
+    // Construct the contact string for the listbox model.
+    iContactStringCreationBuffer.Zero();
+    
+    // Append contact thumbnail id.
+    HBufC* thumbnailId = iContactDataManager->GetThumbnailIdL( aLink, aMatchThumbnails, aFav );
+    iContactStringCreationBuffer.Append( *thumbnailId );
+    delete thumbnailId;
+    iContactStringCreationBuffer.Append( KListFieldSeparatorChar );
+    
+    AppendStringWithMatchDataL(
+            iContactStringCreationBuffer,
+            aContactString,
+            iPredictiveContactSearchHandler,
+            iPredictiveSearchQuery );
+    
+    // Append the whole string to listbox model.
+    iListBoxModel->AppendL( iContactStringCreationBuffer );
+    }
+
+// -----------------------------------------------------------------------------
+// CreateContactStringLC
+//
+// -----------------------------------------------------------------------------
+//
+HBufC* CEasyDialingPlugin::CreateContactStringLC( CPsClientData* aResult,
+        CEasyDialingContactDataManager::TNameOrder aNameOrder )
+    {
+    TPtrC firstName = *aResult->Data( iFirstNamePCSIndex );
+    TPtrC lastName = *aResult->Data( iLastNamePCSIndex );
+    TPtrC companyName( KNullDesC );
+    
+    if ( iCompanyNamePCSIndex != KErrNotFound )
+        {
+        companyName.Set( *aResult->Data( iCompanyNamePCSIndex ) );
+        }
+    return EasyDialingUtils::CreateContactStringLC( firstName, lastName, companyName, aNameOrder );
+    }
+
+
+// -----------------------------------------------------------------------------
+// AddObserverL
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::AddObserverL( MDialingExtensionObserver* aObserver )
+    {
+    if ( !aObserver )
+        {
+        return;
+        }
+    
+    iObservers.AppendL( aObserver );
+    }
+
+
+// -----------------------------------------------------------------------------
+// RemoveObserver
+//
+// Removes the parameter observer from observer list if found. If same observer
+// has registered multiple times (which is unnecessary), removed just the first
+// registration.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::RemoveObserver( MDialingExtensionObserver* aObserver )
+    {
+    for ( TInt i = 0; i < iObservers.Count(); i++ )
+        {
+        if ( iObservers[i] == aObserver)
+            {
+            iObservers.Remove( i );
+            return;
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// InformObservers
+// Informs all registered observers of easy dialing events.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::InformObservers( MDialingExtensionObserver::TEvent aEvent )
+    {
+    for ( TInt i = 0; i < iObservers.Count(); i++ )
+        {
+        iObservers[i]->HandleDialingExtensionEvent( aEvent );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CbaResourceId
+// Returns EasyDialingPlugin specific CBA resource ID that
+// Phone application can use when updating Soft Keys.
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::CbaResourceId()
+    {
+    return R_EASYDIALING_CBA;
+    }
+
+
+// -----------------------------------------------------------------------------
+// MenuResourceId
+// Returns EasyDialingPlugin specific menu resource ID that
+// Phone application can use when easydialing is in focus.
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::MenuResourceId()
+    {
+    return R_EASYDIALING_MENUBAR;
+    }
+
+
+// -----------------------------------------------------------------------------
+// InitializeMenuPaneL
+// Initializes easy dialing menu pane. This function is meant to be called in 
+// DynInitMenuPaneL of the application, if the application wants to use easy
+// dialing menu.
+// -----------------------------------------------------------------------------
+//
+TBool CEasyDialingPlugin::InitializeMenuPaneL( CEikMenuPane& aMenuPane, TInt aMenuResourceId )
+    {   
+    if ( aMenuResourceId == R_PHONEUIDIALER_OPTIONS_MENU )
+        {
+        TInt index( KErrNotFound );
+        // To be on the safe side - place holder was added into phoneui.rss.
+        if ( aMenuPane.MenuItemExists( EEasyDialingSettingsItemPlaceHolder, index ) )
+            {
+            // Add first menu item (= on/off submenu) after placeHolder item and 
+            // then delete that (empty) placeHolder.
+            aMenuPane.AddMenuItemsL( R_EASYDIALING_OPTIONS_ON_OFF_MENU_ITEM, 
+                                     EEasyDialingSettingsItemPlaceHolder );
+            aMenuPane.DeleteMenuItem( EEasyDialingSettingsItemPlaceHolder );
+            
+            LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: Added on/off menu into dialer's menu" );
+            }
+
+        // Return EFalse as only one menu item was added here.
+        return EFalse; 
+        }
+    
+    else if ( aMenuResourceId == R_EASYDIALING_MENU )
+        {
+        TBool voiceCall = EFalse;
+        TBool videoCall = EFalse;
+        TBool message = EFalse;
+        
+        if ( iContactListBox->CurrentItemIndex() >= 0 ) 
+            {
+            TInt index = iContactListBox->CurrentContactDataIndex();
+            
+            voiceCall = iContactDataManager->VoiceCallAvailable( index );
+            videoCall = iContactDataManager->VideoCallAvailable( index );
+            message = iContactDataManager->UniEditorAvailable( index );
+            }
+            
+        
+        aMenuPane.SetItemDimmed( EEasyDialingVoiceCall, !voiceCall ); 
+        aMenuPane.SetItemDimmed( EEasyDialingVideoCall, !videoCall ); 
+        aMenuPane.SetItemDimmed( EEasyDialingSendMessage, !message ); 
+        
+        LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: InitializeMenuPaneL done" );
+        
+        return ETrue;  
+        }
+    
+    else if ( aMenuResourceId == R_EASYDIALING_OPTIONS_ON_OFF_CASCADE_MENU )
+        {
+        if ( IsEnabled() )
+            {
+            aMenuPane.SetItemButtonState( EEasyDialingOn, EEikMenuItemSymbolOn );
+            }
+        else
+            {
+            aMenuPane.SetItemButtonState( EEasyDialingOff, EEikMenuItemSymbolOn );
+            }
+        
+        LOGSTRING("EasyDialingPlugin::InitializeMenuPaneL: InitializeMenuPaneL for on/off submenu done" );
+        
+        return ETrue;
+        }
+    
+    else 
+        {
+        return EFalse;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HandleCommandL
+// Method for handling EasyDialingPlugin specific commands.
+// -----------------------------------------------------------------------------
+//
+TBool CEasyDialingPlugin::HandleCommandL( TInt aCommand )
+    {      
+    // Input blocker can't block controls higher on the control stack than 
+    // ECoeStackPriorityDialog so we will get HandleCommandL calls from 
+    // phoneappui (CBA) when input blocker is active (=not NULL).
+    
+    if ( iInputBlocker && aCommand != EEasyDialingCallHandlingActivated &&
+         aCommand != EEasyDialingVkbOpened && aCommand != EEasyDialingVkbClosed )
+        {
+        // Some action is already being launched since iInputBlocker exists.
+        // Only call activation command requires always action from this plugin.
+        // Vkb status flag should be updated always too (invokes no action).
+        return ETrue;
+        }
+ 
+    
+    TBool ret(ETrue);
+    
+    switch ( aCommand )
+        {
+        case EEasyDialingOpenContact:
+            
+            iRememberFocus = ETrue;
+            AsyncActionLaunchL( ELaunchCurrentContact );
+            break;
+
+        // EEasyDialingEnterKeyAction is sent when Enter key is pressed.
+        // EEasyDialingMakeCall is sent when send key or send toolbar button or send menu item is pressed.
+        case EEasyDialingVoiceCall: // fall through
+        case EEasyDialingEnterKeyAction:
+            // Make a call.
+            iRememberFocus = ETrue;
+            AsyncActionLaunchL( ECallCurrentContact );
+            break;
+            
+        // Video call is selectable only through menu.
+        case EEasyDialingVideoCall:
+            // Make a video call.
+            iRememberFocus = ETrue;
+            AsyncActionLaunchL( EVideoCallCurrentContact );
+            break;
+                
+        // Uni-editor message is selectable only through menu.
+        case EEasyDialingSendMessage:
+            // Create a message.
+            iRememberFocus = ETrue;
+            AsyncActionLaunchL( ESendMessageCurrentContact );
+            break;
+                    
+        // EEasyDialingCallHandlingActivated is sent when the in-call-ui of telephony gets activated
+        case EEasyDialingCallHandlingActivated:
+            
+            iRememberFocus = EFalse;
+            // Stop input block and async action launch in case they are active.
+            CancelActionLaunchAndInputBlock();
+            // Close down number selection popup in case it happens to be open.
+            iContactorService->CancelService();
+            // Close down communication launcher if it's active
+            if ( iContactLauncherActive )
+                {
+                iNewSearchNeeded = EFalse;
+                iContactLauncher->CloseAppL();
+                }
+            break;
+            
+        case EEasyDialingOn:
+            
+            iCenrepListener->SetEasyDialingSettingsValue( 1 );
+            break;
+
+        case EEasyDialingOff:
+            
+            iCenrepListener->SetEasyDialingSettingsValue( 0 );
+            break;    
+            
+        case EEasyDialingClosePopup:
+            
+            // Not only Number Entry is removed but also closes down number selection popup in case it happens to be open.
+            iContactorService->CancelService();
+            break;
+            
+        case EEasyDialingVkbOpened:
+            
+            iVirtualKeyboardOpen = ETrue;
+            break;
+                  
+        case EEasyDialingVkbClosed:
+            
+            iVirtualKeyboardOpen = EFalse;
+            HandleGainingForeground();
+            break;
+            
+        default:
+            ret = EFalse;
+            break;
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// IsEnabled
+// Check if Easy dialing is enabled in the settings
+// -----------------------------------------------------------------------------
+//
+TBool CEasyDialingPlugin::IsEnabled() const
+    {
+    return ( iCenrepListener && iCenrepListener->Value() != 0 );
+    }
+
+// -----------------------------------------------------------------------------
+// SetKeyboardMode
+// Sets keyboard mode
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetKeyboardMode( TKeyboardMode aMode )
+    {
+    iKeyboardMode = aMode;
+    }
+
+// -----------------------------------------------------------------------------
+// AsyncSimulateKeyEvent
+// 
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::AsyncSimulateKeyEvent( const TKeyEvent& aKeyEvent )
+    {
+    // Do the simulation only if input hasn't been blocked
+    if ( !iInputBlocker )
+        {
+        iKeyEventToSimulate = aKeyEvent;
+        iActionToBeLaunched = ESimulateKeyEvent;
+        iAsyncCallBack->SetPriority( CActive::EPriorityStandard );
+        iAsyncCallBack->CallBack(); // activates callback request
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// AsyncActionLaunchL
+// Use asynchronous callback to launch action. While action is being launched,
+// input blocker is used to avoid OfferKeyEvent and HandlePointerEvent calls
+// coming in. Both end key and application key work despite of input blocker.
+// Input blocker can't block phoneappui's cba so extra check is needed in
+// HandleCommandL method.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::AsyncActionLaunchL( TEasyDialingAction aAction )
+    {
+    iActionToBeLaunched = aAction;
+
+    delete iContactToBeLaunched;
+    iContactToBeLaunched = NULL;
+    delete iContactToBeLaunchedName;
+    iContactToBeLaunchedName = NULL;
+       
+    if ( aAction == ECallCurrentContact
+            || aAction == EVideoCallCurrentContact
+            || aAction == ESendMessageCurrentContact
+            || aAction == ELaunchCurrentContact )
+        {
+        // Need to save current contact link and name. Listbox current item
+        // index might not be correct when callback is handled.
+        TRAPD( err, iContactToBeLaunched = iContactListBox->CurrentContactLinkL() );
+        if ( err || !iContactToBeLaunched )
+            {
+            // Can't find contact for the action - probably because listbox
+            // has lost the selection somehow. This shouldn't happen, but if it does
+            // return without trying to launch any action.
+            return;
+            }
+        
+        TPtrC contactString( iListBoxModel->MdcaPoint( iContactListBox->CurrentItemIndex() ) );
+        TPtrC fullNameSeparators;
+        TInt error = TextUtils::ColumnText( fullNameSeparators, 1, &contactString );
+        __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) );
+        
+        // Remove highlight separators. It is possible that some contactor API has problem with them.
+        iContactToBeLaunchedName = AllocWithoutHighlightSeparatorsLC( fullNameSeparators );
+        CleanupStack::Pop( iContactToBeLaunchedName );
+        }
+    
+    CancelActionLaunchAndInputBlock();
+    
+    if ( aAction == ELaunchSearch )
+        {
+        // Must be set as low as possible to enable PCS to update its store.
+        iAsyncCallBack->SetPriority( CActive::EPriorityIdle );
+        }
+    else
+        {
+        iAsyncCallBack->SetPriority( CActive::EPriorityStandard );
+        }
+    
+    iAsyncCallBack->CallBack(); // activates callback request
+    
+    // By defining cancel handler, we don't block all input but system is still
+    // able to deactivate the view etc.
+    iInputBlocker = CAknInputBlock::NewCancelHandlerLC( this );
+    CleanupStack::Pop( iInputBlocker );
+    
+    // This means that iInputBlocker is deleted by CAknInputBlock when
+    // it's cancelled ( we get a callback where iInputBlocker is set to NULL).
+    iInputBlocker->SetCancelDelete( iInputBlocker );
+    }
+
+// -----------------------------------------------------------------------------
+// AsyncCallBackToLaunchAction
+// Callback function for CAsyncCallBack class.
+// -----------------------------------------------------------------------------
+//
+TInt CEasyDialingPlugin::AsyncCallBackToLaunchAction( TAny* aPtr )
+    {
+    CEasyDialingPlugin* plugin = static_cast<CEasyDialingPlugin*>( aPtr );
+    
+    TRAP_IGNORE( plugin->DoLaunchActionL() );
+    
+    // Stop input block if active (=not NULL).
+    if ( plugin->iInputBlocker )
+        {
+        plugin->iInputBlocker->Cancel();
+        }
+    
+    plugin->iActionToBeLaunched = ENoActionDefined;
+    
+    return KErrNone;
+    }
+    
+// -----------------------------------------------------------------------------
+// DoLaunchActionL
+//
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::DoLaunchActionL()
+    {
+    if ( iActionToBeLaunched == EInitializePcs )
+        {
+        PERF_MEASURE_START
+        InitPredictiveContactSearchL();
+        PERF_MEASURE_STOP
+ 
+        return;
+        }
+    else if ( !IsVisible() )
+        {
+        // If ED is not visible, don't launch the action. This can happen if
+        // we get incoming call in the middle of action launching.
+        return;
+        }
+    // If ELaunchCurrentContact, then we launch cca launcher.
+    else if ( iActionToBeLaunched == ELaunchCurrentContact )
+        {
+        LaunchCurrentContactL();
+        return;
+        }
+    else if ( iActionToBeLaunched == ELaunchSearch )
+        {
+        LaunchSearchL();
+        return;
+        }
+    else if ( iActionToBeLaunched == ESimulateKeyEvent )
+        {
+        iEikonEnv->SimulateKeyEventL( iKeyEventToSimulate, EEventKey );
+        return;
+        }
+    
+    // If not for launching current contact or performing search, 
+    // the action is launching some communication method.
+    
+    if ( iContactorService->IsBusy() )
+        {
+        LOGSTRING("EasyDialingPlugin: LaunchActionL - contactor service is busy!");
+        return;
+        }
+ 
+    VPbkFieldTypeSelectorFactory::TVPbkContactActionTypeSelector selector( 
+            VPbkFieldTypeSelectorFactory::EEmptySelector );
+    
+    switch ( iActionToBeLaunched ) 
+        {
+        case ECallCurrentContact:
+            {
+            // Easy Dialing provides pretty much the same functionality for big Call icon 
+            // and Send key than phonebook's contact list view by using aiw interface 
+            // in edcontactor.
+            // At this point one must however check whether to use voip or voice call selector - 
+            // otherwise correct logic is provided by aiw interface.
+            // Note that Easy Dialing ignores default numbers and addresses set for
+            // action types and shows always the number and address list if there are
+            // more than one possible number/address for some action.
+             
+            CSPSettingsVoIPUtils* sPSettings = CSPSettingsVoIPUtils::NewLC();
+            
+            if ( sPSettings->IsPreferredTelephonyVoIP() )
+                {
+                selector = VPbkFieldTypeSelectorFactory::EVOIPCallSelector;
+                }
+            else
+                {
+                selector = VPbkFieldTypeSelectorFactory::EVoiceCallSelector;
+                }
+            
+            CleanupStack::PopAndDestroy( sPSettings );
+            }
+            break;
+            
+        case EVideoCallCurrentContact:
+            
+            selector = VPbkFieldTypeSelectorFactory::EVideoCallSelector;
+            break;
+            
+        case ESendMessageCurrentContact:
+            
+            selector = VPbkFieldTypeSelectorFactory::EUniEditorSelector;
+            break;
+            
+        default:
+            delete iContactToBeLaunched;
+            iContactToBeLaunched = NULL;
+            delete iContactToBeLaunchedName;
+            iContactToBeLaunchedName = NULL;
+            __ASSERT_DEBUG( EFalse, EasyDialingPanic( EEasyDialingActionNotSupported ) );
+            return;
+        }
+
+    CEDContactorService::TCSParameter param( selector, *iContactToBeLaunched, 
+                                             CEDContactorService::TCSParameter::EEnableDefaults, 
+                                             *iContactToBeLaunchedName );
+
+    iContactorService->ExecuteServiceL( param );
+
+    delete iContactToBeLaunched;
+    iContactToBeLaunched = NULL;
+    delete iContactToBeLaunchedName;
+    iContactToBeLaunchedName = NULL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CancelActionLaunchAndInputBlock
+// Should be called when focus is lost or when call ui is activated.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::CancelActionLaunchAndInputBlock()
+    {
+    iAsyncCallBack->Cancel();
+    if ( iInputBlocker )
+        {
+        iInputBlocker->Cancel();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HandleListBoxEventL
+// EasyDialerListBox calls this function when listbox events are reported
+// to observers.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandleListBoxEventL( CEikListBox* /*aListBox*/, TListBoxEvent aEventType )
+    {
+    LOGSTRING1( "EasyDialingPlugin: HandleListBoxEventL( %d ) - Enter", aEventType );
+
+    switch( aEventType )
+        {
+        case EEventItemSingleClicked:
+            // 9.2. Selecting contact initiates call
+            AsyncActionLaunchL( ECallCurrentContact );
+            break;
+
+        case KEasyDialingContactLongTapped:
+            iLongTapped = ETrue;
+            AsyncActionLaunchL( ELaunchCurrentContact );
+            break;
+            
+        // Pause contact data manager when panning and flicking listbox.
+        // This ensures smooth and responsive listbox touch handling.
+        case EEventFlickStarted:
+        case EEventPanningStarted:
+        case KEasyDialingScrollingStarted:
+            iContactDataManager->Pause( ETrue );
+            break;
+            
+        case EEventFlickStopped:
+        case EEventPanningStopped:
+        case KEasyDialingScrollingStopped:
+            iContactListBox->View()->ItemDrawer()->ClearFlags( CListItemDrawer::ESingleClickDisabledHighlight );
+            static_cast<CEasyDialingListBoxView*>( iContactListBox->View() )->SetCurrentItemIndexToNone();
+            iContactDataManager->Pause( EFalse );
+            
+            // Touching the listbox always removes the visual focus from any list item.
+            // Move the focus away from the listbox after panning has ended to
+            // align our internal state with the visual lack of focus.
+            if ( IsFocused() && !iLongTapped )
+                {
+                SetFocus( EFalse );
+                DrawDeferred();
+                }
+            iLongTapped = EFalse;
+            break;
+            
+        // We are not interested about the other listbox events.
+        default:
+            break;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// From MAknInputBlockCancelHandler.
+// Called when input block is cancelled.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::AknInputBlockCancel()
+    {
+    LOGSTRING("EasyDialingPlugin: AknInputBlockCancel");
+    
+    // iInputBlocker will be deleted right after this callback by CAknInputBlock
+    // cause we are using CAknInputBlock::SetCancelDelete method.
+    iInputBlocker = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// HandleGainingForeground
+// From MCoeForegroundObserver.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandleGainingForeground()
+    {
+    if ( iNewSearchNeeded && IsEnabled() )
+        {
+        // The cached information in contact data manager may be outdated. Call to reload makes sure that when the 
+        // search is made, all data is loaded again.
+        iContactDataManager->Reload();
+        
+        TRAP_IGNORE( LaunchSearchL() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HandleLosingForeground
+// From MCoeForegroundObserver.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HandleLosingForeground()
+    {
+    // Make sure contact data manager is not left in paused state when
+    // ED loses foreground while scrolling is active.
+    iContactDataManager->Pause( EFalse );
+    
+    // Simulate an EButton1Up event for scrollbar so that it will be in correct
+    // state if e.g. some popup appears while scrollbar is dragged.
+    // No need to check if scrollbar has received button1Down event or
+    // is indeed dragged currently: no harm done if button1Up is simulated 
+    // in vain.
+    CEikScrollBarFrame* scrollBarFrame = iContactListBox->ScrollBarFrame();
+    if ( scrollBarFrame )
+        {
+        CEikScrollBar* scrollBar = scrollBarFrame->VerticalScrollBar();
+        if ( scrollBar && scrollBar->IsVisible() )
+            {
+            TPointerEvent simulatedPointerEvent( TPointerEvent::EButton1Up, 0,
+                                                 TPoint(), TPoint() );
+            TRAP_IGNORE( scrollBar->HandlePointerEventL( simulatedPointerEvent ) );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::DoHandleContactsChangedL
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::DoHandleContactsChangedL()
+    {
+    if ( iSearchString.Length() > 0 && IsEnabled() )
+        {
+        CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() );
+        if ( appUi->IsForeground() && !iVirtualKeyboardOpen )
+            {
+            // Do new search immediately, if contacts change while we are on the
+            // foreground. This can happen for example if view is switched to
+            // dialer while deletion of multiple contacts is still ongoing or if
+            // PCS takes so long to update the cache that view gets changed 
+            // before the update is ready.
+            iContactDataManager->Reload(); // to update thumbnails
+            AsyncActionLaunchL( ELaunchSearch );
+            }
+        else
+            {
+            // Set the flag to make a search when we come back to foreground.
+            // This way, we don't make unnecessary searches when several
+            // contacts are imported or deleted, for example.
+            iNewSearchNeeded = ETrue;
+            
+            // Hide previous results so that they won't show up before the
+            // the new search is ready.
+            iContactListBox->MakeVisible( EFalse );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::ShowContactListBoxWithEffect
+// Use appear/disappear effects when in foreground and when listbox truly
+// changes visiblity.
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::ShowContactListBoxWithEffect()
+    {
+    if ( !IsVisible() )
+        {
+        // never show listbox if easydialing is not visible
+        return;
+        }
+    // Show effect only if listbox is about to come visible.
+    else if ( !iContactListBox->IsVisible() && CanListBoxEffectBeUsed() )
+        {
+        GfxTransEffect::Begin( iContactListBox, KGfxContactListBoxOpenEffect );
+        iContactListBox->MakeVisible( ETrue );
+        GfxTransEffect::SetDemarcation( iContactListBox, iContactListBox->Rect() );
+        GfxTransEffect::End( iContactListBox );
+        }
+    else
+        {
+        iContactListBox->MakeVisible( ETrue );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::HideContactListBoxWithEffect
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::HideContactListBoxWithEffect()
+    {
+    // Show effect only if listbox is about to disappear from the screen.
+    if ( iContactListBox->IsVisible() && CanListBoxEffectBeUsed() )
+        {
+        GfxTransEffect::Begin( iContactListBox, KGfxContactListBoxCloseEffect );
+        iContactListBox->MakeVisible( EFalse );
+        GfxTransEffect::SetDemarcation( iContactListBox, iContactListBox->Rect() );
+        GfxTransEffect::End( iContactListBox );
+        }
+    else
+        {
+        iContactListBox->MakeVisible( EFalse );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::CanListBoxEffectBeUsed
+// -----------------------------------------------------------------------------
+//
+TBool CEasyDialingPlugin::CanListBoxEffectBeUsed() const
+    {
+    TBool canBeUsed( EFalse );
+    
+    CAknAppUi* appUi = static_cast<CAknAppUi*>( iCoeEnv->AppUi() );
+    
+    // Note that when vkb is open, phone still keeps foreground and focus so
+    // vkb status must be checked separately (vkb's window group has just higher
+    // priority than phone's window group).
+    if ( appUi && appUi->IsForeground() &&
+         !iVirtualKeyboardOpen &&
+         GfxTransEffect::IsEnabled() &&
+         GfxTransEffect::IsRegistered( iContactListBox ) )
+        {
+        canBeUsed = ETrue;
+        }
+    
+    return canBeUsed;
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::SetInfoLabelColourL
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetInfoLabelColourL()
+    {
+    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+    TRgb skinColor;
+    TInt error = AknsUtils::GetCachedColor( skin, skinColor,
+            KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6 );
+            
+    if ( error == KErrNone )
+        {
+        iInfoLabelLine1->OverrideColorL( EColorLabelText, skinColor );
+        iInfoLabelLine2->OverrideColorL( EColorLabelText, skinColor );
+        }    
+    }
+
+// -----------------------------------------------------------------------------
+// CEasyDialingPlugin::SetInfoLabelVisibleL
+// -----------------------------------------------------------------------------
+//
+void CEasyDialingPlugin::SetInfoLabelVisibleL( TBool aVisible )
+    {
+    if ( aVisible )
+        {
+        iInfoLabelLine1->SetTextL( *iInfoLabelTextLine1 );
+        iInfoLabelLine2->SetTextL( *iInfoLabelTextLine2 );
+        }
+    else
+        {
+        iInfoLabelLine1->SetTextL( KNullDesC );
+        iInfoLabelLine2->SetTextL( KNullDesC );
+        }    
+    iInfoLabelLine1->DrawDeferred();
+    iInfoLabelLine2->DrawDeferred();
+    }
+
+
+/*
+ * ==============================================================================
+ * 
+ * Local functions
+ * 
+ * ==============================================================================
+ */
+
+
+
+// -----------------------------------------------------------------------------
+// CompareTPsMatchLocation
+// Compares two TPsMatchLocation objects based on where the match 
+// is located in the search string. This used in ordering matches
+// based on their location.
+// -----------------------------------------------------------------------------
+//
+TInt CompareTPsMatchLocation( const TPsMatchLocation& a1, const TPsMatchLocation& a2)
+    {
+    return a1.index - a2.index;
+    }
+
+
+// -----------------------------------------------------------------------------
+// AppendStringWithMatchDataL
+// Appends a string with match data into a TDes buffer. Match data is a string 
+// where matching and non-matching parts are separated by matching hightlight separator
+// characters.
+// -----------------------------------------------------------------------------
+//
+void AppendStringWithMatchDataL(
+        TDes& aBuffer,
+        const TDesC& aText,
+        CPSRequestHandler* aPSHandler,
+        const CPsQuery* aPSQuery )
+    {
+    if ( HighlightingSupportedForText( aText ) )
+        {
+        CDesCArrayFlat* matchingParts = new (ELeave) CDesCArrayFlat(KEasyDialingMaximumMatchingParts);
+        CleanupStack::PushL( matchingParts );
+     
+        RArray<TPsMatchLocation> matchIndices;
+        CleanupClosePushL( matchIndices );
+        
+        aPSHandler->LookupL( *aPSQuery , aText , *matchingParts, matchIndices );
+        
+        // Sort matchIndices array. Later handling assumes it to be sorted according to index field.
+        TLinearOrder<TPsMatchLocation> order( CompareTPsMatchLocation );
+        matchIndices.Sort( order );
+       
+        TInt numberOfIndices = matchIndices.Count();
+        TInt textOffset = 0;
+        
+        for ( TInt i = 0; i < numberOfIndices ; i++ )
+            {
+            TInt matchingPartStart = matchIndices[i].index;
+            TInt matchingPartLength = matchIndices[i].length;
+            
+            // Append the non-matching part (if exists) 
+            if ( matchingPartStart > textOffset )
+                {
+                TPtrC notMatchingPart = aText.Mid( textOffset, matchingPartStart - textOffset );
+                aBuffer.Append( notMatchingPart );
+                }
+            
+            // Append matching separator charactes.
+            aBuffer.Append( KHighlightSeparatorChar );
+            
+            TPtrC matchingPart = aText.Mid( matchingPartStart, matchingPartLength );
+            aBuffer.Append( matchingPart );
+            
+            // Append matching separator charactes.
+            aBuffer.Append( KHighlightSeparatorChar );
+            
+            textOffset = matchingPartStart + matchingPartLength;
+            }
+
+        CleanupStack::PopAndDestroy( &matchIndices );
+        CleanupStack::PopAndDestroy( matchingParts );
+
+        // Now there still may be one not matching part to be appended.
+        if ( textOffset < aText.Length() )
+            {
+            TPtrC notMatchingPart = aText.Mid( textOffset, aText.Length() - textOffset );
+            aBuffer.Append( notMatchingPart );
+            }
+        }
+    else // HighlightingSupportedForText( aText )
+        {
+        aBuffer.Append( aText );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// HighlightingSupportedForText
+// Checks if highlighting of matching text part is supported for the combination
+// of scripts used in the given text
+// -----------------------------------------------------------------------------
+//
+TBool HighlightingSupportedForText( const TDesC& aText )
+    {
+    // Highlighting for text is supported unless it contains one ore more
+    // characters written with unsupported script.
+    TBool supported = ETrue;
+    for ( TInt i = 0 ; i < aText.Length() && supported ; ++i )
+        {
+        supported = HighlightingSupportedForScript( aText[i] );
+        }
+    
+    // ... or it contains both LTR and RTL blocks
+    if ( supported )
+        {
+        supported = !IsStrictlyBidirectional( aText );
+        }
+    
+    return supported;
+    }
+
+// -----------------------------------------------------------------------------
+// HighlightingSupportedForScript
+// Checks if highlighting of matching text part is supported for the script
+// of given character
+// -----------------------------------------------------------------------------
+//
+TBool HighlightingSupportedForScript( TText aChar )
+    {
+    // For now, we don't support highlighting for any Arabic or South East Asian 
+    // script. This is because many of these scripts use rendering rules
+    // which cause problems for our simple highlighting logic designed for
+    // Latin script.
+
+    TBool belongsToUnsupportedRange = 
+        ( aChar >= KArabicAndSouthEastAsianRangeStart && aChar <= KArabicAndSouthEastAsianRangeEnd ) ||
+        ( aChar >= KArabicPresentationFormsARangenStart && aChar <= KArabicPresentationFormsARangeEnd ) ||
+        ( aChar >= KArabicPresentationFormsBRangenStart && aChar <= KArabicPresentationFormsBRangeEnd );
+    return !belongsToUnsupportedRange;
+    }
+
+// -----------------------------------------------------------------------------
+// IsStrictlyBidirectional
+// 
+// Returns true if argument descriptor contains both left-to-right and
+// right-to-left blocks
+// -----------------------------------------------------------------------------
+//
+TBool IsStrictlyBidirectional( const TDesC& aText )
+    {
+    TBool bothDirectionsFound = EFalse;
+    
+    // TRunInfoArray contains information of the directionalities of the different sections of the aText    
+    TBidirectionalState::TRunInfo array[ KMaxRunInfoArrayCount ];
+    
+    // Initialize the TBidiLogicalToVisual converter for making the conversion from logical to visual order
+    TBidiLogicalToVisual converter( aText, array, KMaxRunInfoArrayCount );
+    
+    // Do the reordering. Amount of different directionality sections is returned.
+    TInt blockCount = converter.Reorder();
+    if ( blockCount > KMaxRunInfoArrayCount )
+        {
+        // If there are  more directionality blocks than we are prepared to handle, then we don't
+        // know the directionality of them all. Report this as bidirectional to be on the safe side.
+        // This should be an extremely rare special case.
+        bothDirectionsFound = ETrue;
+        }
+    else if ( blockCount > 1 )
+        {
+        // If there are more than one directionality blocks, go through all of them and
+        // check if the resolved direction changes in any of the blocks.
+        TUint8 firstDirection = array[0].iDirection;
+        for ( TInt i = 1 ; i < blockCount && !bothDirectionsFound ; i++ )
+            {
+            if ( array[i].iDirection != firstDirection )
+                {
+                bothDirectionsFound = ETrue;
+                }
+            }
+        }
+
+    return bothDirectionsFound;
+    }
+
+
+// -----------------------------------------------------------------------------
+// AllocWithoutHighlightSeparatorsLC
+// 
+// Allocates a copy of the parameter descriptor with highlight separators 
+// removed.
+// -----------------------------------------------------------------------------
+//
+static HBufC* AllocWithoutHighlightSeparatorsLC( const TDesC& aDesc )
+    {
+    HBufC* resultDesc = aDesc.AllocLC();
+    TPtr ptr = resultDesc->Des();
+    AknTextUtils::StripCharacters( ptr, KHighlightSeparatorCharAsLiteral );
+    return resultDesc;
+    }
+
+
+// -----------------------------------------------------------------------------
+// IsItuTCharacter
+// 
+// Test whether parameter character is a number pad character "0123456789#*+"
+// -----------------------------------------------------------------------------
+//
+static TBool IsItuTCharacter( TChar aChar )
+    {
+    return aChar.IsDigit() || 
+         aChar.GetCategory() == TChar::EArabicNumber ||
+         aChar == TChar('#') ||
+         aChar == TChar('*') ||
+         aChar == TChar('+');
+    }
+
+// -----------------------------------------------------------------------------
+// Find contact link pointing to the same contact as given link
+// -----------------------------------------------------------------------------
+//
+static TInt Find( const MVPbkContactLink* aLink, const RPointerArray<MVPbkContactLink>& aArray )
+    {
+    TInt idx = KErrNotFound;
+    for ( TInt i = 0 ; i < aArray.Count() ; ++i )
+        {
+        if ( aArray[i]->IsSame( *aLink ) )
+            {
+            idx = i;
+            i = aArray.Count();
+            }
+        }
+    return idx;
+    }
+
+// -----------------------------------------------------------------------------
+// CleanupStack helpers for item owning RPointerArrays (etc)
+// -----------------------------------------------------------------------------
+//
+template <class T>
+class CleanupResetAndDestroy
+    {
+public:
+    inline static void PushL( T& aRef )
+        { CleanupStack::PushL( TCleanupItem(&ResetAndDestroy,&aRef) ); }
+private:
+    inline static void ResetAndDestroy( TAny *aPtr )
+        { static_cast<T*>(aPtr)->ResetAndDestroy(); }
+    };
+
+template <class T>
+inline void CleanupResetAndDestroyPushL( T& aRef )
+    { CleanupResetAndDestroy<T>::PushL(aRef); }
+
+//  End of File
+