diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/src/aknindicatorpopupcontent.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/src/aknindicatorpopupcontent.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,1552 @@ +/* +* Copyright (c) 2007,2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Content that is shown inside a universal status +* indicator popup. +* +*/ + + +// SYSTEM INCLUDE FILES + +#include +#include +#include +#include +#include "akndigitalclock.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for testability hooks +#include + + +// USER INCLUDE FILES +#include "aknindicatorpopupcontent.h" +#include "aknindicatorpopup.h" +#include "AknBatteryIcon.h" +#include "AknSignalIcon.h" + + +// CONSTANTS + +/** Granularity of the indicator item array. */ +const TInt KItemArrayGranularity = 8; + +/** Path to the clock application, launched directly from the popup. */ +_LIT( KClockApplication, "\\sys\\bin\\clock.exe" ); + +/** Internal state flags. */ +enum TIndicatorPopupContentFlags + { + /** Pointer down event has happened inside this control. */ + EAknIndicatorPopupContentButton1Down = 0x00000001, + /** Clock application is being launched. */ + EAknIndicatorPopupContentClockBeingLaunched = 0x00000002 + }; + +const TInt KBatteryAreaIndex = 0; +const TInt KSignalAreaIndex = 1; + + +// ============================================================================= +// CAknIndicatorPopupItem +// Item class declaration & definition. +// ============================================================================= +// +NONSHARABLE_CLASS( CAknIndicatorPopupItem ) : public CBase + { +public: + + /** + * Default constructor. + * + * @param aUid UID of the indicator. + * @param aPlugin Pointer to the indicator's ECOM plugin, + * can be NULL. + * @param aPriority Display priority of the indicator. + * @param aTextType Type of the item text. + */ + CAknIndicatorPopupItem( TInt aUid, + CAknIndicatorPlugin* aPlugin, + TInt aPriority, + TInt aTextType ); + + /** + * Destructor. + */ + ~CAknIndicatorPopupItem(); + + /** + * Second-phase constructor to be used with custom icon. + * + * @param aText Item text. + * @param aIcon Indicator icon. + */ + void ConstructL( const TDesC& aText, + const CGulIcon* aIcon ); + + /** + * Second-phase constructor to be used with the default + * indicator icon. + * + * @param aText Item text. + * @param aIconID Index of the indicator icon. + * @param aIconID Index of the indicator icon mask. + */ + void ConstructL( const TDesC& aText, + TInt aIconID, + TInt aIconMaskID ); + + /** + * Sets the area of this item in the popup. + * + * @param aRect Rectangle of this item, relative + * to the popup. + */ + void SetRect( const TRect& aRect ); + + /** + * Changes the indicator icon of the item or updates + * the color when skin changes. + * + * @param aIcon Pointer to the new icon if the icon + * is to be changed. + */ + void UpdateIndicatorIconL( const CGulIcon* aIcon = NULL ); + + /** + * Updates the item text. + * + * @param aText Item text. + */ + void UpdateTextL( const TDesC& aText, TInt aTextType ); + + /** + * Draws the item. + * + * @param aGc Reference to the window graphics context. + */ + void DrawItem( CWindowGc& aGc ); + +public: // Member data + + /** UID of the indicator. */ + TInt iUid; + + /** Indicator priority. */ + TInt iPriority; + + /** Item text, owned. */ + HBufC* iText; + + /** Type of the text. */ + TInt iTextType; + + /** Item area. */ + TRect iRect; + + /** Indicator icon area. */ + TRect iIconRect; + + /** Default indicator icon, owned. */ + CGulIcon* iIcon; + + /** Custom indicator icon, not owned. */ + const CGulIcon* iCustomIcon; + + /** Index of the default indicator icon. */ + TInt iIconID; + + /** Index of the default indicator icon mask. */ + TInt iIconMaskID; + + /** Pointer to the indicator plugin, not owned. */ + CAknIndicatorPlugin* iPlugin; + }; + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::CAknIndicatorPopupItem +// Default constructor +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupItem::CAknIndicatorPopupItem( TInt aUid, + CAknIndicatorPlugin* aPlugin, + TInt aPriority, + TInt aTextType ) + : iUid( aUid ), + iPriority( aPriority ), + iTextType( aTextType ), + iPlugin( aPlugin ) + { + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::CAknIndicatorPopupItem +// Destructor +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupItem::~CAknIndicatorPopupItem() + { + delete iText; + delete iIcon; + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::ConstructL +// Second-phase constructor +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::ConstructL( const TDesC& aText, + const CGulIcon* aIcon ) + { + delete iText; + iText = NULL; + iText = aText.AllocL(); + + iCustomIcon = aIcon; + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::ConstructL +// Second-phase constructor +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::ConstructL( const TDesC& aText, + TInt aIconID, + TInt aIconMaskID ) + { + delete iText; + iText = NULL; + iText = aText.AllocL(); + + iIconID = aIconID; + iIconMaskID = aIconMaskID; + + UpdateIndicatorIconL(); + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::SetRect +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::SetRect( const TRect& aRect ) + { + iRect = aRect; + + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( + iRect, + AknLayoutScalable_Avkon::list_single_uniindi_pane_g1() ); + iIconRect = layoutRect.Rect(); + + CFbsBitmap* bitmap = NULL; + + if ( iCustomIcon ) + { + bitmap = iCustomIcon->Bitmap(); + } + else if ( iIcon ) + { + bitmap = iIcon->Bitmap(); + } + + if ( bitmap ) + { + AknIconUtils::SetSize( bitmap, + iIconRect.Size(), + EAspectRatioPreserved ); + } + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::UpdateIndicatorIconL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::UpdateIndicatorIconL( const CGulIcon* aIcon ) + { + if ( iCustomIcon && + !aIcon ) + { + // Custom icon in use + if ( iPlugin ) + { + iCustomIcon = NULL; + TRAPD( err, iCustomIcon = iPlugin->IconL( iUid ) ); + + if ( !err && iCustomIcon ) + { + // Icon update succeeded. + AknIconUtils::SetSize( iCustomIcon->Bitmap(), + iIconRect.Size(), + EAspectRatioPreserved ); + return; + } + + // Else use the default icon. + } + } + + delete iIcon; + iIcon = NULL; + + if ( aIcon ) + { + iCustomIcon = aIcon; + + AknIconUtils::SetSize( iCustomIcon->Bitmap(), + iIconRect.Size(), + EAspectRatioPreserved ); + } + else + { + CFbsBitmap* bitmap; + CFbsBitmap* mask; + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + AknsUtils::CreateColorIconLC( + skin, + KAknsIIDDefault, + KAknsIIDQsnIconColors, + EAknsCIQsnIconColorsCG20, + bitmap, + mask, + KAvkonBitmapFile, + iIconID, + iIconMaskID, + KRgbGray ); + + AknIconUtils::SetSize( bitmap, + iIconRect.Size(), + EAspectRatioPreserved ); + + iIcon = CGulIcon::NewL( bitmap, mask ); + + CleanupStack::Pop( 2, bitmap ); + } + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::UpdateTextL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::UpdateTextL( const TDesC& aText, TInt aTextType ) + { + delete iText; + iText = NULL; + iText = aText.AllocL(); + iTextType = aTextType; + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupItem::DrawItem +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupItem::DrawItem( CWindowGc& aGc ) + { + // Use custom icon if it exists. + const CGulIcon* icon = iCustomIcon; + if ( !icon ) + { + icon = iIcon; + } + + if ( icon && icon->Bitmap() && icon->Mask() ) + { + aGc.BitBltMasked( iIconRect.iTl, + icon->Bitmap(), + iIconRect.Size(), + icon->Mask(), + ETrue ); + } + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + TAknTextLineLayout textLayout( + AknLayoutScalable_Avkon::list_single_uniindi_pane_t1().LayoutLine() ); + + TRgb textColor; + + if ( iTextType == CAknIndicatorPlugin::EAknIndicatorPluginLinkText ) + { + aGc.SetUnderlineStyle( EUnderlineOn ); + AknsUtils::GetCachedColor( skin, + textColor, + KAknsIIDQsnHighlightColors, + EAknsCIQsnHighlightColorsCG3 ); + } + else + { + AknsUtils::GetCachedColor( skin, + textColor, + KAknsIIDQsnTextColors, + EAknsCIQsnTextColorsCG55 ); + } + + TAknLayoutText layoutText; + layoutText.LayoutText( iRect, textLayout ); + layoutText.DrawText( aGc, *iText, ETrue, textColor ); + + aGc.SetUnderlineStyle( EUnderlineOff ); + } + + +// ============================================================================= +// CAknIndicatorPopupContent +// ============================================================================= +// + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::NewL +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupContent* CAknIndicatorPopupContent::NewL() + { + CAknIndicatorPopupContent* self = CAknIndicatorPopupContent::NewLC(); + CleanupStack::Pop( self ); + return self; + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::NewLC +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupContent* CAknIndicatorPopupContent::NewLC() + { + CAknIndicatorPopupContent* self = new (ELeave) CAknIndicatorPopupContent; + CleanupStack::PushL( self ); + self->ConstructL(); + AKNTASHOOK_ADDL( self, "CAknIndicatorPopupContent" ); + return self; + } + + +// ----------------------------------------------------------------------------- +// Destructor. +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupContent::~CAknIndicatorPopupContent() + { + AKNTASHOOK_REMOVE(); + // Ensure here that this popup is removed from the global + // popup priority stack. + AknGlobalPopupPriorityController::RemovePopupPriority( *this ); + + iItems.ResetAndDestroy(); + iItems.Close(); + + delete iClock; + delete iBattery; + delete iSignal; + + if ( iBatteryPlugin || iSignalPlugin ) + { + delete iBatteryPlugin; + delete iSignalPlugin; + REComSession::FinalClose(); + } + + MTouchFeedback* feedback = MTouchFeedback::Instance(); + if ( feedback ) + { + feedback->RemoveFeedbackForControl( this ); + } + + delete iSeparatorIcon; + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::MinimumSize +// ----------------------------------------------------------------------------- +// +TSize CAknIndicatorPopupContent::MinimumSize() + { + TInt items( iItems.Count() ); + + // Get the maximum number of indicator items from layout data. + TAknLayoutScalableParameterLimits limits( + AknLayoutScalable_Avkon::list_single_uniindi_pane_ParamLimits() ); + TInt variety( limits.LastRow() + 1 ); // Last variety for no indicator items + + if ( items > 0 ) + { + if ( items <= variety ) + { + variety -= items; + } + else + { + variety = 0; // Maximum number of items. + } + } + + TRect applicationWindow; + AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EApplicationWindow, + applicationWindow ); + + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( + applicationWindow, + AknLayoutScalable_Avkon::popup_uni_indicator_window( variety ) ); + + return TSize( layoutRect.Rect().Size() ); + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::HandleResourceChange +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::HandleResourceChange( TInt aType ) + { + CCoeControl::HandleResourceChange( aType ); + + TInt itemCount( iItems.Count() ); + + switch ( aType ) + { + case KAknsMessageSkinChange: + { + // Update clock text color. + TRgb textColor; + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + AknsUtils::GetCachedColor( skin, + textColor, + KAknsIIDQsnTextColors, + EAknsCIQsnTextColorsCG55 ); + + iClock->SetColor( textColor ); + + // Update signal icon. + iSignal->SetColorIndex( 0 ); // reset skin color + TRAP_IGNORE( SetSignalStateL( iSignalState ) ); + // Color of the battery indicator is changed by it's container. + iBattery->HandleResourceChange( aType ); + // Update the signal icon and separator line color. + TRAP_IGNORE( LoadIconsL() ); + + // Update the color of the indicator icons. + for ( TInt i = 0; i < itemCount; i++ ) + { + TRAP_IGNORE( iItems[i]->UpdateIndicatorIconL() ); + } + break; + } + + case KEikMessageFadeAllWindows: + { + if ( !Window().IsFaded() ) + { + Window().SetFaded( ETrue, + RWindowTreeNode::EFadeIncludeChildren ); + } + break; + } + + case KEikMessageUnfadeWindows: + { + if ( Window().IsFaded() ) + { + Window().SetFaded( EFalse, + RWindowTreeNode::EFadeIncludeChildren ); + } + break; + } + + default: + break; + } + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::HandlePointerEventL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::HandlePointerEventL( + const TPointerEvent& aPointerEvent ) + { + if ( Rect().Contains( aPointerEvent.iPosition ) ) + { + CBase* currentFocusedItem = NULL; + switch ( aPointerEvent.iType ) + { + case TPointerEvent::EButton1Down: + // Set flag that down was inside the popup. + iFlags |= EAknIndicatorPopupContentButton1Down; + iPreviousPressedDownItem = NULL; + + if ( iClock->Rect().Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iClock; + iPressedDownRect = iClockPressedDownArea; + } + else if ( iSignalArea.Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iSignal; + iPressedDownRect = iSignalPressedDownArea; + } + else if ( iBatteryArea.Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iBattery; + iPressedDownRect = iBatteryArea; + } + else + { + CAknIndicatorPopupItem* item = TappedItem( aPointerEvent.iPosition ); + if ( item ) + { + currentFocusedItem = item; + iPressedDownRect = item->iRect; + } + else + // No item get tapped + { + return; + } + } + iEnablePressedDownState = ETrue; + Window().Invalidate( iPressedDownRect ); + iPreviousPressedDownItem = currentFocusedItem; + break; + + case TPointerEvent::EDrag: + if ( iClock->Rect().Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iClock; + } + else if ( iSignalArea.Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iSignal; + } + else if ( iBatteryArea.Contains( aPointerEvent.iPosition )) + { + currentFocusedItem = iBattery; + } + else + { + currentFocusedItem = TappedItem( aPointerEvent.iPosition ); + } + + if( currentFocusedItem != iPreviousPressedDownItem ) + { + iFlags &= ~EAknIndicatorPopupContentButton1Down; + iEnablePressedDownState = EFalse; + Window().Invalidate( iPressedDownRect ); + } + break; + + case TPointerEvent::EButton1Up: + if ( iFlags & EAknIndicatorPopupContentButton1Down ) + { + // Up happened, reset button down flag. + iFlags &= ( ~EAknIndicatorPopupContentButton1Down ); + iEnablePressedDownState = EFalse; + + if ( iBatteryPlugin && + iBatteryArea.Contains( aPointerEvent.iPosition ) ) + { + ReportEventL( + static_cast( + EAknIndicatorPopupTapEvent ) ); + + // Dummy value used as indicator UID parameter, + // as it's not used by the battery indicator plugin. + iBatteryPlugin->HandleIndicatorTapL( 0 ); + break; + } + else if ( iSignalPlugin && + iSignalArea.Contains( aPointerEvent.iPosition ) ) + { + ReportEventL( + static_cast( + EAknIndicatorPopupTapEvent ) ); + + // Dummy value used as indicator UID parameter, + // as it's not used by the signal indicator plugin. + iSignalPlugin->HandleIndicatorTapL( 0 ); + break; + } + else if ( iClock && + iClock->Rect().Contains( aPointerEvent.iPosition ) ) + { + ReportEventL( + static_cast( + EAknIndicatorPopupTapEvent ) ); + + if ( !( iFlags & EAknIndicatorPopupContentClockBeingLaunched ) ) + { + // Start clock application directly when down event + // happens in clock, this functionality was previously + // in the CAknDigitalClock. + RApaLsSession apa; + User::LeaveIfError( apa.Connect() ); + CleanupClosePushL( apa ); + CApaCommandLine* cmdLine = CApaCommandLine::NewLC(); + cmdLine->SetExecutableNameL( KClockApplication ); + cmdLine->SetCommandL( EApaCommandRun ); + User::LeaveIfError( apa.StartApp( *cmdLine ) ); + CleanupStack::PopAndDestroy( 2, &apa ); // cmdLine and apa + + // Set the flag indicating that clock is being launched. + iFlags |= EAknIndicatorPopupContentClockBeingLaunched; + } + } + + CAknIndicatorPopupItem* item = TappedItem( aPointerEvent.iPosition ); + if ( item ) + { + ReportEventL( + static_cast( + EAknIndicatorPopupTapEvent ) ); + + item->iPlugin->HandleIndicatorTapL( item->iUid ); + break; + } + } + break; + + default: + break; + } + } + else if ( iFlags & EAknIndicatorPopupContentButton1Down )// Drag to outside + { + iFlags &= ~EAknIndicatorPopupContentButton1Down; + iEnablePressedDownState = EFalse; + Window().Invalidate( iPressedDownRect ); + } + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::CountComponentControls +// ----------------------------------------------------------------------------- +// +TInt CAknIndicatorPopupContent::CountComponentControls() const + { + TInt count = 0; + + if ( iClock ) + { + count++; + } + + if ( iBattery ) + { + count++; + } + + if ( iSignal ) + { + count++; + } + + return count; + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::ComponentControl +// ----------------------------------------------------------------------------- +// +CCoeControl* CAknIndicatorPopupContent::ComponentControl( TInt aIndex ) const + { + CCoeControl* componentControl = NULL; + + switch ( aIndex ) + { + case 0: + componentControl = iClock; + break; + case 1: + componentControl = iBattery; + break; + case 2: + componentControl = iSignal; + break; + default: + break; + } + + return componentControl; + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl. +// CAknIndicatorPopupContent::SetContainerWindowL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::SetContainerWindowL( + const CCoeControl& aContainer ) + { + CCoeControl::SetContainerWindowL( aContainer ); + + if( iClock ) + { + iClock->SetContainerWindowL( aContainer ); + } + } + + +// --------------------------------------------------------------------------- +// CAknIndicatorPopupContent::AddItemL +// --------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::AddItemL( TInt aIndicatorUid, + const TDesC& aText, + TInt aTextType, + const CGulIcon* aIcon, + CAknIndicatorPlugin* aPlugin, + TInt aPriority ) + { + TInt itemCount( iItems.Count() ); + for ( TInt i = 0; i < itemCount; i++ ) + { + if ( iItems[i]->iUid == aIndicatorUid ) + { + // Indicator item exists already. + return; + } + } + + CAknIndicatorPopupItem* newItem = + new (ELeave) CAknIndicatorPopupItem( aIndicatorUid, + aPlugin, + aPriority, + aTextType ); + + if ( aIcon ) + { + // If the plugin provides an icon, use it. + newItem->ConstructL( aText, aIcon ); + } + else + { + // Otherwise use the same icon as in the indicator pane. + TInt bitmapID; + TInt maskID; + + CAknIndicator::GetBitmapIndexL( + CAknIndicatorContainer::EUniversalIndicators, + aIndicatorUid, + bitmapID, + maskID ); + + newItem->ConstructL( aText, bitmapID, maskID ); + } + + if ( aPlugin ) + { + aPlugin->SetPluginObserver( this ); + } + + iItems.AppendL( newItem ); + + // Discard possible pressed down highlight when the popup size changes, + // as the position of the highlighted item may change. + iEnablePressedDownState = EFalse; + + SizeChanged(); + } + + +// --------------------------------------------------------------------------- +// CAknIndicatorPopupContent::RemoveItem +// --------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::RemoveItem( TInt aIndicatorUid ) + { + TInt itemCount( iItems.Count() ); + for ( TInt i = 0; i < itemCount; i++ ) + { + if ( iItems[i]->iUid == aIndicatorUid ) + { + delete iItems[i]; + iItems[i] = NULL; + iItems.Remove( i ); + break; + } + } + + // Discard possible pressed down highlight when the popup size changes, + // as the position of the highlighted item may change. + iEnablePressedDownState = EFalse; + + SizeChanged(); + } + + +// --------------------------------------------------------------------------- +// CAknIndicatorPopupContent::SetContentVisible +// --------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::SetContentVisible( TBool aVisible ) + { + if ( aVisible ) + { + SizeChanged(); // also includes UpdateFeedbackAreas() + } + if ( iClock ) + { + // The clock timer needs to be running only when the + // popup is visible. + if ( aVisible ) + { + // Error ignored, if this leaves then the clock + // is not updated if time changes while popup is visible. + iClock->StartTimer(); + } + else + { + iClock->StopTimer(); + } + } + + + if ( !aVisible ) + { + // Remove this popup from the global popup priority stack. + AknGlobalPopupPriorityController::RemovePopupPriority( *this ); + + // Clear the state flags. + iFlags &= ( ~EAknIndicatorPopupContentButton1Down ); + iFlags &= ( ~EAknIndicatorPopupContentClockBeingLaunched ); + } + else + { + // Add this popup from the global popup priority stack so + // that it can receive key events. + // Note that the popup priority is not set, so it has + // priority the default priority, which is 0. + AknGlobalPopupPriorityController::ShowPopup( *this, ETrue ); + } + } + +// --------------------------------------------------------------------------- +// CAknIndicatorPopupContent::SetBatteryStateL +// --------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::SetBatteryStateL( TInt aState ) + { + if ( iBattery ) + { + iBattery->SetBatteryIconL( aState ); + } + } +// --------------------------------------------------------------------------- +// CAknIndicatorPopupContent::SetSignalStateL +// --------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::SetSignalStateL( TInt aState ) + { + TInt newState( aState ); + + if ( iSignal ) + { + if ( newState == KAknSignalOffLineMode ) + { + // Set offline state icon to the signal area. + iSignal->SetOffLine( ETrue ); + } + else if ( newState == KAknSignalOffLineMode - 1 ) + { + // This aState parameter is used to inform about connection + // state change from offline mode. Signal icon is set not + // to be in offline state and the correct signal state is + // used from iSignalState. + iSignal->SetOffLine( EFalse ); + newState = iSignalState; + } + iSignal->LoadIconL( newState, EAknsCIQsnIconColorsCG5 ); + } + + // Ensure that the new value is valid, offline mode state is + // not stored as a signal state. + if ( newState >= 0 && + newState <= EAknSignalHsdpaIndicatorMultipdp ) // last signal state + { + iSignalState = newState; + } + } +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::HandlePluginUpdateL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::HandlePluginUpdateL( TInt aUid ) + { + TInt itemCount( iItems.Count() ); + for ( TInt i = 0; i < itemCount; i++ ) + { + if ( iItems[i]->iUid == aUid && + iItems[i]->iPlugin ) // Can update only if we have a + { // pointer to the plugin. + // Update text + TInt textType; + HBufC* text = iItems[i]->iPlugin->TextL( aUid, textType ); + if ( text ) + { + CleanupStack::PushL( text ); + iItems[i]->UpdateTextL( *text, textType ); + CleanupStack::PopAndDestroy( text ); + } + + // Update icon + const CGulIcon* icon = NULL; + TRAPD( err, icon = iItems[i]->iPlugin->IconL( aUid ) ); + if ( !err && icon ) + { + iItems[i]->UpdateIndicatorIconL( icon ); + } + + break; + } + } + + DrawDeferred(); + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::UpdateAllIndicatorsL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::UpdateAllIndicatorsL() + { + CAknIndicatorPlugin* plugin = NULL; + TInt itemCount( iItems.Count() ); + + for ( TInt i = 0; i < itemCount; i++ ) + { + plugin = iItems[i]->iPlugin; + + if ( plugin ) // Can update only if we have a + { // pointer to the plugin. + TInt uid( iItems[i]->iUid ); + + // Update text + TInt textType; + HBufC* text = plugin->TextL( uid, textType ); + if ( text ) + { + CleanupStack::PushL( text ); + iItems[i]->UpdateTextL( *text, textType ); + CleanupStack::PopAndDestroy( text ); + } + + // Update icon + const CGulIcon* icon = NULL; + TRAPD( err, icon = plugin->IconL( uid ) ); + if ( !err && icon ) + { + iItems[i]->UpdateIndicatorIconL( icon ); + } + } + } + } + + +// ----------------------------------------------------------------------------- +// Default constructor. +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupContent::CAknIndicatorPopupContent() + : iItems( KItemArrayGranularity ) + { + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::ConstructL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::ConstructL() + { + iClock = CAknDigitalClock::NewL( this ); + TAknTextLineLayout clockLayout( + AknLayoutScalable_Avkon::uniindi_top_pane_t1( 1 ).LayoutLine() ); + + // Ensure that the left and right values of the clock text layout + // are zero, currently the whole top area is set as the parent + // for this layout, so it's narrowed by reducting the + // signal pane area. + clockLayout.il = 0; + clockLayout.ir = 0; + iClock->SetTimeLayout( clockLayout ); + TRgb textColor; + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + AknsUtils::GetCachedColor( skin, + textColor, + KAknsIIDQsnTextColors, + EAknsCIQsnTextColorsCG55 ); + iClock->SetColor( textColor ); + + iBattery = CAknBatteryIcon::NewL(); + iBattery->SetContainerWindowL( *this ); + iSignal = CAknSignalIcon::NewL(); + iSignal->SetContainerWindowL( *this ); + + // Create default signal icon. + iSignal->LoadIconL( 0, EAknsCIQsnIconColorsCG5 ); + + // Set this to draw the icon also in offline mode. + iSignal->SetOffLineIconDraw( ETrue ); + TRAPD( err, iBatteryPlugin = CAknIndicatorPlugin::NewL( + TUid::Uid( KImplUIDBatteryIndicatorPlugin ) ) ); + if ( err == KErrNone ) + { + iBatteryPlugin->SetPluginObserver( this ); + } + TRAPD( err1, iSignalPlugin = CAknIndicatorPlugin::NewL( + TUid::Uid( KImplUIDSignalIndicatorPlugin ) ) ); + if ( err1 == KErrNone ) + { + iSignalPlugin->SetPluginObserver( this ); + } + + iFeedback = MTouchFeedback::Instance(); + + // Load the separator line and signal icon graphics. + LoadIconsL(); + + iEnablePressedDownState = EFalse; + iPreviousPressedDownItem = NULL; + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::PrioritizeIndicatorsL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::PrioritizeIndicatorsL() + { + TInt count = iItems.Count(); + if ( count < 2 ) + { + return; + } + + CAknIndicatorPopupItem* temp; + for ( TInt ii = 1; ii < count; ii++ ) + { + temp = iItems[ii]; + TInt tempPriority = temp->iPriority; + + if ( tempPriority >= 0 ) + { + for ( TInt jj = 0; jj <= ii; jj++ ) + { + TInt indicatorPriority = iItems[jj]->iPriority; + + if ( tempPriority < indicatorPriority ) + { + iItems.Remove( ii ); + iItems.InsertL( temp, jj ); + break; + } + else if ( jj == ( ii - 1 ) ) + { + break; + } + } + } + } + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::UpdateFeedbackAreas +// +// Digital clock takes care of its own feedback, but we have to either +// enable or block feedback for signal indicator, according to +// wheather it has associated plug-in or not (if it has plug-in, then +// something happens when it is tapped and feedback should be produced). +// +// In addition we have to set feedback to every item, which acts as a link. +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::UpdateFeedbackAreas() + { + if ( iFeedback ) + { + // First remove all old feedback areas + iFeedback->RemoveFeedbackForControl( this ); + if ( iBatteryPlugin ) + { + // Set battery indicator's feedback area + CFeedbackSpec* fbSpec = CFeedbackSpec::New(); + if ( fbSpec ) + { + fbSpec->AddFeedback( ETouchEventStylusDown, + ETouchFeedbackSensitiveButton ); + fbSpec->AddFeedback( ETouchEventStylusUp, + ETouchFeedbackSensitiveButton, + ETouchFeedbackVibra ); + + iFeedback->SetFeedbackArea( this, + KBatteryAreaIndex, + iBatteryArea, + fbSpec ); + delete fbSpec; + } + } + + if ( iSignalPlugin ) + { + // Set signal indicator's feedback area + CFeedbackSpec* fbSpec = CFeedbackSpec::New(); + if ( fbSpec ) + { + fbSpec->AddFeedback( ETouchEventStylusDown, + ETouchFeedbackSensitiveButton ); + fbSpec->AddFeedback( ETouchEventStylusUp, + ETouchFeedbackSensitiveButton, + ETouchFeedbackVibra ); + + iFeedback->SetFeedbackArea( this, + KSignalAreaIndex, + iSignalArea, + fbSpec ); + delete fbSpec; + } + } + + // Go through the items, and set feedback areas for those which act + // as link (i.e. have associated plugin) + TInt itemCount( iItems.Count() ); + + for ( TInt i = 0; i < itemCount; i++ ) + { + if ( iItems[i]->iPlugin && + iItems[i]->iTextType == + CAknIndicatorPlugin::EAknIndicatorPluginLinkText && + iItems[i]->iRect != TRect( 0, 0, 0, 0 ) ) + { + CFeedbackSpec* fbSpec = CFeedbackSpec::New(); + if ( fbSpec ) + { + fbSpec->AddFeedback( ETouchEventStylusDown, + ETouchFeedbackSensitiveButton ); + + iFeedback->SetFeedbackArea( this, + KSignalAreaIndex + i + 1, + iItems[i]->iRect, + fbSpec ); + delete fbSpec; + } + } + } + } + } + + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::LoadIconsL +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::LoadIconsL() + { + TRect rect( Rect() ); + + delete iSeparatorIcon; + iSeparatorIcon = NULL; + + CFbsBitmap* bitmap = NULL; + CFbsBitmap* mask = NULL; + + AknsUtils::CreateColorIconL( AknsUtils::SkinInstance(), + KAknsIIDQgnGrafLineVerticalFade, + KAknsIIDQsnLineColors, + EAknsCIQsnLineColorsCG3, + bitmap, + mask, + KNullDesC, + KErrNotFound, + KErrNotFound, + KRgbGray ); + + iSeparatorIcon = CGulIcon::NewL( bitmap, mask ); + + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( + rect, + AknLayoutScalable_Avkon::uniindi_top_pane() ); + + layoutRect.LayoutRect( + layoutRect.Rect(), + AknLayoutScalable_Avkon::uniindi_top_pane_g3( 1 ) ); + + AknIconUtils::SetSize( iSeparatorIcon->Bitmap(), + layoutRect.Rect().Size(), + EAspectRatioNotPreserved ); + + // + // Create a custom signal icon for connectivity manager link. + // + + CFbsBitmap* signalBitmap = NULL; + CFbsBitmap* signalMask = NULL; + + AknsUtils::CreateColorIconL( AknsUtils::SkinInstance(), + KAknsIIDQgnPropLinkConnectionManager, + KAknsIIDQsnIconColors, + EAknsCIQsnIconColorsCG5, + signalBitmap, + signalMask, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_prop_link_connection_manager, + EMbmAvkonQgn_prop_link_connection_manager_mask, + KRgbGray ); + + // Ownership is transferred. + iSignal->SetSignalIcon( signalBitmap ); + iSignal->SetSignalIconMask( signalMask ); + } + +// ----------------------------------------------------------------------------- +// CAknIndicatorPopupContent::TappedItem +// ----------------------------------------------------------------------------- +// +CAknIndicatorPopupItem* +CAknIndicatorPopupContent::TappedItem(const TPoint& aPoint) const + { + for ( TInt ii = 0; ii < iItems.Count(); ii++ ) + { + CAknIndicatorPopupItem* item = iItems[ii]; + if ( item->iRect.Contains( aPoint ) && item->iPlugin + && item->iTextType == + CAknIndicatorPlugin::EAknIndicatorPluginLinkText ) + { + return item; + } + } + return NULL; + } + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::SizeChanged +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::SizeChanged() + { + TRect rect( Rect() ); + + // Popup window top area + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( rect, + AknLayoutScalable_Avkon::uniindi_top_pane() ); + TRect topRect( layoutRect.Rect() ); + + // Signal pane area + layoutRect.LayoutRect( topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g1() ); + TRect signalRect( layoutRect.Rect() ); + + // Battery pane area + layoutRect.LayoutRect( topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g2() ); + TRect batteryRect( layoutRect.Rect() ); + + // Clock pane area + layoutRect.LayoutRect( topRect, + AknLayoutScalable_Avkon::aid_area_touch_clock() ); + TRect clockRect( layoutRect.Rect() ); + + // Separator line size + layoutRect.LayoutRect( + topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g3() ); + TRect separatorRect = layoutRect.Rect(); + TSize separatorSize( layoutRect.Rect().Size() ); + + TBool layoutMirrored( AknLayoutUtils::LayoutMirrored() ); + + iClock->SetRect( clockRect ); + iBattery->SetRect( batteryRect ); + iSignal->SetRect( signalRect ); + + // Make the touch responsive areas of signal pane + // slightly larger by not taking into account the margins from + // top and sides. + iBatteryArea = batteryRect; + iSignalArea = signalRect; + + if ( layoutMirrored ) + { + iBatteryArea.iTl = topRect.iTl; + iBatteryArea.iBr.iY = topRect.iBr.iY; + iSignalArea.iBr = topRect.iBr; + iSignalArea.iTl.iY = topRect.iTl.iY; + } + else + { + iBatteryArea.iBr = topRect.iBr; + iBatteryArea.iTl.iY = topRect.iTl.iY; + iBatteryArea.iTl.iX = clockRect.iBr.iX; + iSignalArea.iTl = topRect.iTl; + iSignalArea.iBr.iY = topRect.iBr.iY; + } + + // Calculate permanent component press down effect rect + iSignalPressedDownArea = iSignalArea; + iClockPressedDownArea = clockRect; + + // Indicator area + layoutRect.LayoutRect( rect, + AknLayoutScalable_Avkon::list_uniindi_pane() ); + TRect listRect( layoutRect.Rect() ); + + TRAP_IGNORE( PrioritizeIndicatorsL() ); + + TAknLayoutScalableParameterLimits limits( + AknLayoutScalable_Avkon::list_single_uniindi_pane_ParamLimits() ); + TInt maxNumberOfIndicatorsShown = limits.LastRow(); + + TInt itemCount( iItems.Count() ); + + for ( TInt i = 0; i < itemCount; i++ ) + { + if ( i <= maxNumberOfIndicatorsShown ) + { + layoutRect.LayoutRect( + listRect, + AknLayoutScalable_Avkon::list_single_uniindi_pane( 0, 0, i ) ); + iItems[i]->SetRect( layoutRect.Rect() ); + } + else + { + iItems[i]->SetRect( TRect( 0, 0, 0, 0 ) ); + } + } + + UpdateFeedbackAreas(); + + AknIconUtils::SetSize( iSeparatorIcon->Bitmap(), + separatorSize, + EAspectRatioNotPreserved ); + + DrawDeferred(); + } + + +// ----------------------------------------------------------------------------- +// From class CCoeControl +// CAknIndicatorPopupContent::Draw +// ----------------------------------------------------------------------------- +// +void CAknIndicatorPopupContent::Draw( const TRect& aRect ) const + { + if ( AknLayoutUtils::PenEnabled() ) + { + CWindowGc& gc = SystemGc(); + + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + + TRect rect( Rect() ); + + TAknLayoutRect layoutRect; + layoutRect.LayoutRect( + rect, + AknLayoutScalable_Avkon::uniindi_top_pane() ); + TRect topRect( layoutRect.Rect() ); + + layoutRect.LayoutRect( + topRect, + AknLayoutScalable_Avkon::bg_uniindi_top_pane( 1 ) ); + TRect topCenterRect( layoutRect.Rect() ); + layoutRect.LayoutRect( + topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g3() ); + TRect leftSeparatorRect( layoutRect.Rect() ); + + layoutRect.LayoutRect( + topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g3( 1 ) ); + TRect separatorRect( layoutRect.Rect() ); + + layoutRect.LayoutRect( + topRect, + AknLayoutScalable_Avkon::uniindi_top_pane_g4() ); + TRect rightSeparatorRect( layoutRect.Rect() ); + + // Draw the button frame to the permanent items area. + AknsDrawUtils::DrawFrame( skin, + gc, + topRect, + topCenterRect, + KAknsIIDQsnFrPopupHeading, + KAknsIIDQsnFrPopupHeadingCenter ); + if ( iEnablePressedDownState ) + { + AknsDrawUtils::DrawFrame( skin, + gc, + iPressedDownRect, + iPressedDownRect, + KAknsIIDQsnFrListPressed, + KAknsIIDQsnFrListCenterPressed); + } + CFbsBitmap* bitmap = iSeparatorIcon->Bitmap(); + CFbsBitmap* mask = iSeparatorIcon->Mask(); + + // Draw the separator line on the top pane. + gc.BitBltMasked( leftSeparatorRect.iTl, + bitmap, + leftSeparatorRect.Size(), + mask, + ETrue ); + + gc.BitBltMasked( rightSeparatorRect.iTl, + bitmap, + rightSeparatorRect.Size(), + mask, + ETrue ); + + // Draw the indicator items. + for ( TInt i = 0; i < iItems.Count(); i++ ) + { + if ( aRect.Intersects( iItems[i]->iRect ) ) + { + iItems[i]->DrawItem( gc ); + } + } + } + }