uifw/AvKon/akncompamode/src/akncompakb.cpp
changeset 0 2f259fa3e83a
child 51 fcdfafb36fe7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/akncompamode/src/akncompakb.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,616 @@
+/*
+* 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:  Compatibility mode keyboard UI component
+*
+*/
+
+
+#include <e32base.h>
+#include <AknsUtils.h> 
+#include <AknsSkinInstance.h>
+#include <AknsDrawUtils.h>
+#include <AknsBasicBackgroundControlContext.h>
+#include <centralrepository.h>
+#include <AvkonInternalCRKeys.h>
+#include <pslninternalcrkeys.h>
+#include <aknlayoutscalable_avkon.cdl.h>
+
+#include "akncompakb.h"
+#include "akncompaside.h"
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaKb* CAknCompaKb::NewL(TInt aCompaScreenMode, TBool aMakeVisible)
+    {
+    CAknCompaKb* self = new (ELeave) CAknCompaKb(aCompaScreenMode);
+    CleanupStack::PushL(self);
+    self->ConstructL(aMakeVisible);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::ConstructL(TBool aMakeVisible)
+    {
+    // Connect to key server is not delayed until buttons are pressed
+    // as we don't want application to fail while it's executing due
+    // to a key press.
+    // Optimization: akncapserver/aknnfysrv/eiksrv have compakeyboard
+    // always instantiated. akncapserver/aknnfysrv simulate raw events
+    // without compakeysrv. Eikon server doesn't have capability to
+    // simulate raw events directly. In this case connection to the key
+    // server press is delayed until a key is pressed. This way key server
+    // is not running all the time.
+    RProcess process;
+    TSecureId secureId = process.SecureId();
+    iFlags.iInEikSrv = AknCompaUtils::IsEikSrv(secureId);
+    iFlags.iInAknCapSrv = AknCompaUtils::IsAknCapSrv(secureId);
+    iFlags.iInGlobalUiSrv = AknCompaUtils::IsGlobalUiSrv(secureId);
+    if (!iFlags.iInGlobalUiSrv)
+        {
+        User::LeaveIfError(iCompaSrvSession.Connect());
+        iThemesCenRep = CRepository::NewL(KCRUidThemes);
+        }
+
+    // Transition effects do not work in compa-mode (centered window). They
+    // are disabled when screen mode is compa-mode. In case device was
+    // powered off while effects were disabled, restore transition effects
+    // state.
+    if (iFlags.iInAknCapSrv)
+        {
+        // Enable transition effects if device was powered off while
+        // we had them disabled.
+        if (iCompaSrvSession.Connect() == KErrNone)
+            {
+            iCompaSrvSession.RestoreTransEffects();
+            iCompaSrvSession.Close();
+            }
+        }
+
+    CreateWindowL();
+    RWindow& window = Window();
+    // Prevent fading when application displays a dialog
+    window.SetNonFading(ETrue);
+    // Ordinal priority is not usually set for application windows
+    // (only for window groups). Compa keyboard is set to high ordinary
+    // priority. This keeps it always at front and prevents other windows
+    // (eg. menus, dialogs) capturing pointer events.
+    // If an application would set one it's own windows to higher
+    // priority, it could capture pointer events but menus and dialogs
+    // wouldn't work either in that case.
+    const TInt KOrdinalPriority = ECoeWinPriorityAlwaysAtFront + 1;
+    window.SetOrdinalPosition(window.OrdinalPosition(), KOrdinalPriority);
+    // Request pointer up event event if stylus is dragged out of this window
+    window.SetPointerGrab(ETrue);
+    // Capture pointer events from this window group. This prevents
+    // touch working in application window even when the application
+    // doesn't observe layout's PenEnabled.
+    window.SetPointerCapture(RWindowBase::TCaptureEnabled);
+    
+    iBgContext = CAknsBasicBackgroundControlContext::NewL(
+        KAknsIIDQsnBgScreen, Rect(), ETrue);
+
+    // Get skin background, this method is used to update it also
+    SkinChanged();
+
+    // Construct buttons
+    AknCompaUtils::ReadButtonsL(iButtons, iPenButtonIndex, *iCoeEnv);
+    for(TInt i = 0; i < iButtons.Count(); i++)
+        {
+        CAknCompaButton* button = iButtons[i];
+        button->SetContainerWindowL(*this);
+        button->SetObserver(button);
+        }
+
+    iLeftSide = CAknCompaSide::NewL();
+    iRightSide = CAknCompaSide::NewL();
+    
+    // Set constrol and buttons size and position. If control is left
+    // invisible, screen mode is not compa-mode and layout is postponed
+    // until screen mode is compa-mode.
+    if (aMakeVisible)
+        {
+        LayoutControl();
+        }
+
+    // Add to control stack to receive KEikDynamicLayoutVariantSwitch
+    // events
+    iCoeEnv->AppUi()->AddToStackL(this, ECoeStackPriorityDefault,
+        ECoeStackFlagRefusesAllKeys);
+
+    iCoeEnv->AddForegroundObserverL(*this);
+
+    // Compa-mode keyboard is made visible in the case of a normal
+    // applications. Compa-keyboard is also created for servers
+    // that display global/notes notifications but left invisible.
+    // Visibility of the keyboard is controlled according to current
+    // screen mode. It's visible only in compa screen mode. Note:
+    // It's also possible for a screen mode to change (e.g. due to
+    // some application exiting) while a global note is on display.
+    if (aMakeVisible)
+        {
+        ActivateL();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// Constructor
+// --------------------------------------------------------------------------
+CAknCompaKb::CAknCompaKb(TInt aCompaScreenMode):
+    iButtons(EButtonsGranularity)
+    {
+    iCompaScreenMode = aCompaScreenMode;
+    }
+
+// --------------------------------------------------------------------------
+// Destructor
+// --------------------------------------------------------------------------
+CAknCompaKb::~CAknCompaKb()
+    {
+    iCoeEnv->AppUi()->RemoveFromStack(this);
+    iCoeEnv->RemoveForegroundObserver(*this);
+
+    iButtons.ResetAndDestroy();
+    delete iLeftSide;
+    delete iRightSide;
+
+    delete iBgContext;
+
+    // Keyserver sends up events if client has any keys in down state
+    // when session is closed
+    iCompaSrvSession.Close();
+
+    delete iThemesCenRep;
+    }
+
+// --------------------------------------------------------------------------
+// Simulate a key press to application
+// --------------------------------------------------------------------------
+void CAknCompaKb::SimulateKeyPressL(TInt aScanCode, TBool aDown)
+    {
+    if (!iFlags.iInGlobalUiSrv)
+        {
+        // Key press is simulated via a server as SwEvent capability
+        // is needed
+        iCompaSrvSession.SimulateKeyEventL(aScanCode, aDown);
+        }
+    else if (iFlags.iInEikSrv)
+        {
+        // Eikon server. Connect to key server only when needed.
+        // Connection to key server should succeed as it is already
+        // started by an application that set screen mode to compa.
+        if (iCompaSrvSession.Handle() == KNullHandle)
+            {
+	        User::LeaveIfError( iCompaSrvSession.Connect() );
+            }
+        if (iCompaSrvSession.Handle() != KNullHandle)
+            {
+            iCompaSrvSession.SimulateKeyEventL(aScanCode, aDown);
+            }
+        }
+    else
+        {
+        // akncapserver and aknnfysrv don't use compakeysrv
+        TRawEvent rawEvent;        
+        rawEvent.Set(
+            aDown ? TRawEvent::EKeyDown:TRawEvent::EKeyUp, aScanCode);
+        RWsSession& wsSession = iCoeEnv->WsSession();
+        wsSession.SimulateRawEvent(rawEvent);
+        wsSession.Flush();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// Set "pen" button to up state
+// --------------------------------------------------------------------------
+void CAknCompaKb::SetPenButtonUpL()
+    {
+    if (iPenButtonIndex != KErrNotFound)
+        {
+        CAknCompaButton* compaButton = iButtons[iPenButtonIndex];
+        if (compaButton->IsPressed())
+            {
+            compaButton->SetButtonUpL();
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// Set buttons to up state
+// --------------------------------------------------------------------------
+void CAknCompaKb::SetButtonsUpL()
+    {
+    TInt cnt = iButtons.Count();
+    for(TInt i = 0; i < cnt; i++)
+        {
+        CAknCompaButton* compaButton = iButtons[i];
+        if (compaButton->IsPressed())
+            {
+            compaButton->SetButtonUpL();            
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// Check is compa-mode application is on foreground
+// --------------------------------------------------------------------------
+TBool CAknCompaKb::IsForeground()
+    {
+    // Voice command application is launched on top of foreground application
+    // in QHD mode. If it is launched on top of compa-mode application
+    // the screen gets messed up. Compa-mode app is showing behind voice
+    // dialer but wserv right shifting is lost. Workaround for this is to
+    // switch idle screen to foreground before voice commander is launched.
+    // Switch to idle screen if this is a regular application or if global
+    // note is showing on top of compa-mode application.
+    return !iFlags.iInGlobalUiSrv || InCompaScreenMode();
+    }
+
+// --------------------------------------------------------------------------
+// Disable transition effects in compa-mode
+// --------------------------------------------------------------------------
+void CAknCompaKb::DisaTransEffects(bool aDisable)
+    {
+    // Transition effects cannot be disabled per application. They can be
+    // disabled globally from central repository. Transition effects are
+    // disabled whenever screen mode changes to compa-mode by AknCapServer.
+    if (iFlags.iInAknCapSrv && iFlags.iEffectsDisa != aDisable)
+        {
+        if (iCompaSrvSession.Handle() == KNullHandle)
+            {
+	        User::LeaveIfError( iCompaSrvSession.Connect() );
+            }
+        if (iCompaSrvSession.Handle() != KNullHandle)
+            {
+            if (aDisable)
+                {
+                iCompaSrvSession.DisaTransEffects();
+                }
+            else
+                {
+                iCompaSrvSession.RestoreTransEffects();
+                iCompaSrvSession.Close();
+                }
+            iFlags.iEffectsDisa = aDisable;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Return wanted layout rectangle
+// ---------------------------------------------------------------------------
+TRect CAknCompaKb::RectFromLayout( const TRect& aParent,
+    const TAknWindowComponentLayout& aComponentLayout )
+    {
+    TAknLayoutRect layoutRect;
+    layoutRect.LayoutRect(aParent, aComponentLayout.LayoutLine());
+         
+    return layoutRect.Rect();
+    }
+
+// --------------------------------------------------------------------------
+// Layout compamode controls
+// --------------------------------------------------------------------------
+void CAknCompaKb::LayoutControl()
+    {   
+    TPoint origin =
+        iCoeEnv->ScreenDevice()->GetScreenModeOrigin(iCompaScreenMode);
+    
+    TRect screenRect;
+    AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screenRect);
+    
+    // parent rect for all compamode components      
+    iCompaRect = RectFromLayout(screenRect,
+        AknLayoutScalable_Avkon::compa_mode_pane());
+                  
+    TRect compaKbRect = RectFromLayout(iCompaRect,
+        AknLayoutScalable_Avkon::compa_mode_pane_g3());
+       
+    AknCompaUtils::ScaleRect(compaKbRect, -origin.iX, 0);    
+    SetRect(compaKbRect);    
+    
+    // side controls
+    TRect leftSide = RectFromLayout(iCompaRect,
+        AknLayoutScalable_Avkon::compa_mode_pane_g1());
+    
+    TRect rightSide = RectFromLayout(iCompaRect,
+        AknLayoutScalable_Avkon::compa_mode_pane_g2());
+    
+    AknCompaUtils::ScaleRect(rightSide, -origin.iX, 0); 
+    iRightSide->SetRect(rightSide);
+    
+    // Support for not centered compa window.
+    // Left side control has to be moved to other side if not centered
+    if(origin.iX == 0)
+        {
+        origin.iX -= screenRect.Width();
+        }
+
+    AknCompaUtils::ScaleRect(leftSide, -origin.iX, 0);   
+    iLeftSide->SetRect(leftSide);
+         
+    LayoutButtonControls();   
+    SetSkinBackground();
+    iFlags.iLayoutDone = ETrue;
+    }
+
+// --------------------------------------------------------------------------
+// Layout button controls
+// --------------------------------------------------------------------------
+void CAknCompaKb::LayoutButtonControls()
+    {                  
+    TRect rockerRect = RectFromLayout(iCompaRect,
+        AknLayoutScalable_Avkon::main_comp_mode_rocker_pane_cp());
+
+    TRect ituRect = RectFromLayout(iCompaRect,
+        AknLayoutScalable_Avkon::main_comp_mode_itu_pane_cp());
+    
+    if (iButtons.Count() > 0)
+        {
+        TAknLayoutScalableParameterLimits buttonLimits =
+            AknLayoutScalable_Avkon::cell_cmode_rocker_pane_cp_ParamLimits();
+
+        // Calculating number of rocker pane buttons
+        iRockerGridSize = ((buttonLimits.LastRow() + 1) *
+            (buttonLimits.LastColumn() + 1));
+
+        TInt buttonCount = 0;
+  
+        LayoutButtonGrid(rockerRect, buttonCount, buttonLimits.LastRow(),
+            buttonLimits.LastColumn());
+
+        buttonLimits =
+            AknLayoutScalable_Avkon::cell_cmode_itu_pane_cp_ParamLimits();
+
+        LayoutButtonGrid(ituRect, buttonCount, buttonLimits.LastRow(),
+            buttonLimits.LastColumn());
+
+        for(TInt i = 0; i < iButtons.Count(); i++)
+            {
+            CAknCompaButton* button = iButtons[i];        
+            TRect rect = button->Rect();    
+            AknCompaUtils::ScaleRect(rect, 0, -iCompaRect.Height());
+                    
+            button->SetRect(rect);    
+            button->UpdateColors();
+            button->LayoutIconAndText();
+            }
+        }
+    }
+
+
+// --------------------------------------------------------------------------
+// Layout grid of buttons
+// --------------------------------------------------------------------------
+void CAknCompaKb::LayoutButtonGrid(TRect aParentRect, TInt& aButtonCount,
+    TInt aRows, TInt aColumns)
+    {
+    for(TInt row = 0; row <= aRows; row++)
+        {
+        for(TInt col = 0; col <= aColumns; col++)
+            {
+            if(aButtonCount < iRockerGridSize)
+                {
+                AknLayoutUtils::LayoutControl(iButtons[aButtonCount],
+                    aParentRect, AknLayoutScalable_Avkon::
+                    cell_cmode_rocker_pane_cp(0,col,row));
+                }
+            else
+                {
+                AknLayoutUtils::LayoutControl(iButtons[aButtonCount],
+                    aParentRect, AknLayoutScalable_Avkon::
+                    cell_cmode_itu_pane_cp(0,col,row));
+                }
+            aButtonCount++;
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// 
+// --------------------------------------------------------------------------
+void CAknCompaKb::SetSkinBackground()
+    {
+    TPoint origin =
+        iCoeEnv->ScreenDevice()->GetScreenModeOrigin(iCompaScreenMode);
+    
+    TPoint origo(0, 0);
+
+    // Skin background context
+    iBgContext->SetParentPos(origo);
+    AknCompaUtils::ScaleRect(iCompaRect, -origin.iX, 0);
+    iBgContext->SetRect(iCompaRect);
+    
+    iLeftSide->SetBackground(origin);
+    iRightSide->SetBackground(origin);
+    
+    }
+
+// --------------------------------------------------------------------------
+// Check if current screen mode is compa-mode
+// --------------------------------------------------------------------------
+TBool CAknCompaKb::InCompaScreenMode()
+    {
+    return iCoeEnv->ScreenDevice()->CurrentScreenMode() ==
+        iCompaScreenMode;
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+TInt CAknCompaKb::CountComponentControls() const
+    {
+    return iButtons.Count();
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CCoeControl* CAknCompaKb::ComponentControl(TInt aIndex) const
+    {
+    return iButtons[aIndex];
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::Draw(const TRect& aRect) const
+    {
+    CWindowGc& gc = SystemGc();
+    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+   
+    // If skin background draw fails, flat color will be used
+    if(!AknsDrawUtils::Background(skin, iBgContext, this, gc, aRect))
+        {
+        gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+        gc.SetPenColor(iSkinColor);
+        gc.SetBrushColor(iSkinColor);     
+        gc.DrawRect(Rect());
+        }
+
+    gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+    gc.SetPenColor(iSkinColor);
+    gc.SetBrushColor(iSkinColor);
+
+    // Draw background rects for rocker buttons.
+    // These are drawn under the buttons to achieve transparency effect.    
+    for(TInt i = 0; i < iButtons.Count(); i++)
+        {
+        CAknCompaButton* button = iButtons[i];
+           
+        if (button->IsRocker())
+            {
+            gc.DrawRect(button->Rect());
+            }
+        }  
+    }
+    
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::HandleResourceChange(TInt aType)
+    {
+    switch(aType)
+        {
+        // Compa-mode application is fixed to QVGA layout and cannot change.
+        // When Avkon notify server is displaying a global note, it's
+        // possible for layout to change. Compa-keyboard is hidden if
+        // screen mode changes out of compa-mode.
+        case KEikDynamicLayoutVariantSwitch:
+            {
+            TBool isScreenModeCompa = InCompaScreenMode();
+            if (isScreenModeCompa && !iFlags.iLayoutDone)
+                {
+                // In global UI-servers, buttons size and position is set
+                // only when compa-mode is entered first time.
+                if (!iFlags.iLayoutDone)
+                    {
+                    LayoutControl();
+                    // In practise ActivateL() will not leave as it allocates
+                    // no resources
+                    TRAP_IGNORE(ActivateL());
+                    }
+                }
+            else
+                {
+                if (iFlags.iLayoutDone && iFlags.iInGlobalUiSrv)
+                    {
+                    MakeVisible(isScreenModeCompa);
+                    }
+                }
+            }
+            break;
+        case KAknsMessageSkinChange:
+            SkinChanged();
+            break;
+        default:
+            break;
+        }
+    CCoeControl::HandleResourceChange(aType);
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::ActivateL()
+    {
+    iLeftSide->ActivateL();
+    iRightSide->ActivateL();
+    CCoeControl::ActivateL();
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::MakeVisible(TBool aVisible)
+    {
+    CCoeControl::MakeVisible(aVisible);
+    iLeftSide->MakeVisible(aVisible);
+    iRightSide->MakeVisible(aVisible);
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::HandleGainingForeground()
+    {
+    iFlags.iForeground = ETrue;
+
+    // Wait for transition effects to go into disabled. This is needed
+    // in WINSCW as effects use CFbsBitGc::SetClippingRegion() which
+    // panics. Global ui-servers may also be in foreground when screen
+    // mode changes to foreground. For example when screen saver deactivates.
+    // In this case they disable effects in KEikDynamicLayoutVariantSwitch
+    // event and rely on timing of there being no draw events before effects
+    // are disabled.
+    if (!iFlags.iInGlobalUiSrv)
+        {
+        AknCompaUtils::WaitTransEffectsOff(*iThemesCenRep);
+        }
+    }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaKb::HandleLosingForeground()
+    {
+    iFlags.iForeground = EFalse;
+
+    // AknAppUi filters stylus up events even if app leaves foreground.
+    // Bring all buttons up to prevent them being left down.
+    TRAP_IGNORE(SetButtonsUpL());
+
+    // If running in eikon server, close connection to key server in
+    // order to allow it to exit if no compa mode applications are
+    // running
+    if (iFlags.iInEikSrv)
+        {
+        iCompaSrvSession.Close();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// Handle skin change event
+// --------------------------------------------------------------------------
+void CAknCompaKb::SkinChanged()
+    {
+    MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+
+    // Update color for rocker button backgrounds
+    AknsUtils::GetCachedColor(skin, iSkinColor, KAknsIIDQsnTextColors,
+        EAknsCIQsnTextColorsCG20);
+    }