diff -r 544e34b3255a -r 91c2fb4b78df phoneuis/easydialing/src/easydialingplugin.cpp --- a/phoneuis/easydialing/src/easydialingplugin.cpp Wed Apr 14 15:56:42 2010 +0300 +++ b/phoneuis/easydialing/src/easydialingplugin.cpp Tue Apr 27 16:37:10 2010 +0300 @@ -328,6 +328,8 @@ 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 @@ -461,20 +463,14 @@ { TKeyResponse keyResponse = EKeyWasNotConsumed; - if ( aKeyEvent.iCode == 0 && aKeyEvent.iScanCode != EStdKeyDevice3) + if ( aType != EEventKey ) { return keyResponse; } TInt keyCode = aKeyEvent.iCode; - // Swap right and left key codes in mirrored layout. This needs to be done - // also for action menu grid as CAknGrid handles arrow keys like this: - // left key = next column (not item!) and right is previous column and - // grid layout (LtR/RtL) is not taken into account when movement is done - // in columns (always like in LtR layout). So if right key should move - // focus to the right also in mirroded layout, key codes must be switched. - // This kind of approach is used also e.g. in application grid. + // Swap right and left key codes in mirrored layout. if ( AknLayoutUtils::LayoutMirrored() ) { if ( keyCode == EKeyRightArrow ) keyCode = EKeyLeftArrow; @@ -534,6 +530,21 @@ { // 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 ); + } } } @@ -966,23 +977,13 @@ // Current implementation searches only from default database. // Later this may be expanded to search SIM contacts as well. - HBufC* default_cdb = VPbkContactStoreUris::DefaultCntDbUri().AllocLC(); - - iPredictiveContactSearchHandler->GetDataOrderL( *default_cdb, fieldOrder ); + const TDesC& defaultCdb = VPbkContactStoreUris::DefaultCntDbUri(); - for ( TInt i = 0; i < fieldOrder.Count(); i++) - { - if ( fieldOrder[i] == aIndex ) - { - CleanupStack::PopAndDestroy( default_cdb ); - CleanupStack::PopAndDestroy( &fieldOrder ); - return i; - } - } + iPredictiveContactSearchHandler->GetDataOrderL( defaultCdb, fieldOrder ); + TInt pcsIndex = fieldOrder.Find( aIndex ); - CleanupStack::PopAndDestroy( default_cdb ); CleanupStack::PopAndDestroy( &fieldOrder ); - return KErrNotFound; + return pcsIndex; } @@ -1106,10 +1107,25 @@ 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(); } else @@ -1218,10 +1234,20 @@ // Ownership of parameter transferred to CCA launcher => pop but do not destroy. CleanupStack::Pop( launchParameters ); - - iContactLauncherActive = ETrue; - CAknAppUi* appUi = static_cast( iCoeEnv->AppUi() ); - appUi->HandleCommandL( EPhoneCmdBlockingDialogLaunched ); + 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( iCoeEnv->AppUi() ); + appUi->HandleCommandL( EPhoneCmdBlockingDialogLaunched ); + } } @@ -1455,10 +1481,12 @@ // ECoeStackPriorityDialog so we will get HandleCommandL calls from // phoneappui (CBA) when input blocker is active (=not NULL). - if ( iInputBlocker && aCommand != EEasyDialingCallHandlingActivated ) + 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; } @@ -1536,6 +1564,18 @@ ret = ETrue; break; + case EEasyDialingVkbOpened: + + iVirtualKeyboardOpen = ETrue; + ret = ETrue; + break; + + case EEasyDialingVkbClosed: + + iVirtualKeyboardOpen = EFalse; + ret = ETrue; + break; + default: break; } @@ -1553,6 +1593,23 @@ } // ----------------------------------------------------------------------------- +// 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 @@ -1561,7 +1618,7 @@ // HandleCommandL method. // ----------------------------------------------------------------------------- // -void CEasyDialingPlugin::AsyncActionLaunchL( const TEasyDialingAction aAction ) +void CEasyDialingPlugin::AsyncActionLaunchL( TEasyDialingAction aAction ) { iActionToBeLaunched = aAction; @@ -1618,8 +1675,22 @@ // 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. - if ( iActionToBeLaunched == ELaunchCurrentContact ) + else if ( iActionToBeLaunched == ELaunchCurrentContact ) { LaunchCurrentContactL(); return; @@ -1629,12 +1700,9 @@ LaunchSearchL(); return; } - else if ( iActionToBeLaunched == EInitializePcs ) + else if ( iActionToBeLaunched == ESimulateKeyEvent ) { - PERF_MEASURE_START - InitPredictiveContactSearchL(); - PERF_MEASURE_STOP - + iEikonEnv->SimulateKeyEventL( iKeyEventToSimulate, EEventKey ); return; } @@ -1787,14 +1855,52 @@ // 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; - } +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() + { + } + +// ----------------------------------------------------------------------------- +// 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 @@ -1826,13 +1932,14 @@ // ----------------------------------------------------------------------------- // void CEasyDialingPlugin::ShowContactListBoxWithEffect() - { - CAknAppUi* appUi = static_cast( iCoeEnv->AppUi() ); - + { + if ( !IsVisible() ) + { + // never show listbox if easydialing is not visible + return; + } // Show effect only if listbox is about to come visible. - if ( !iContactListBox->IsVisible() && - appUi && appUi->IsForeground() && - GfxTransEffect::IsRegistered( iContactListBox ) ) + else if ( !iContactListBox->IsVisible() && CanListBoxEffectBeUsed() ) { GfxTransEffect::Begin( iContactListBox, KGfxContactListBoxOpenEffect ); iContactListBox->MakeVisible( ETrue ); @@ -1851,12 +1958,8 @@ // void CEasyDialingPlugin::HideContactListBoxWithEffect() { - CAknAppUi* appUi = static_cast( iCoeEnv->AppUi() ); - // Show effect only if listbox is about to disappear from the screen. - if ( iContactListBox->IsVisible() && - appUi && appUi->IsForeground() && - GfxTransEffect::IsRegistered( iContactListBox ) ) + if ( iContactListBox->IsVisible() && CanListBoxEffectBeUsed() ) { GfxTransEffect::Begin( iContactListBox, KGfxContactListBoxCloseEffect ); iContactListBox->MakeVisible( EFalse ); @@ -1869,6 +1972,30 @@ } } +// ----------------------------------------------------------------------------- +// CEasyDialingPlugin::CanListBoxEffectBeUsed +// ----------------------------------------------------------------------------- +// +TBool CEasyDialingPlugin::CanListBoxEffectBeUsed() const + { + TBool canBeUsed( EFalse ); + + CAknAppUi* appUi = static_cast( 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; + } + /* * ============================================================================== *