--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/akncompamode/srv/src/akncompaserver.cpp Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,476 @@
+/*
+* Copyright (c) 2007 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:
+*
+*/
+
+
+#include <e32svr.h>
+#include <e32uid.h>
+#include <coemain.h> // CCoeEnv
+#include <apgtask.h> // TApaTaskList and friends
+#include <centralrepository.h>
+#include <AvkonInternalCRKeys.h>
+#include <pslninternalcrkeys.h>
+#include <AknCapServerDefs.h>
+#include <AknNotifierWrapperDefs.h>
+
+#include "akncompasrv.h"
+#include "akncompaserver.h"
+
+// Flags for KAknCompaModeEffects
+const TInt KAknCompaModeEffectsSaved = (1 << 31);
+const TInt KAknCompaModeEffectsDisabled = 0x7fffffff;
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaSrvWsEventHandler::CAknCompaSrvWsEventHandler(RWsSession& aWsSession)
+ : CActive(CActive::EPriorityStandard), iWsSession(aWsSession)
+ {
+ CActiveScheduler::Add(this);
+ IssueRequest();
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaSrvWsEventHandler::~CAknCompaSrvWsEventHandler()
+ {
+ Cancel();
+ }
+
+// --------------------------------------------------------------------------
+// Issue request to read from wsrv event queue
+// --------------------------------------------------------------------------
+void CAknCompaSrvWsEventHandler::IssueRequest()
+ {
+ iWsSession.EventReady(&iStatus);
+ SetActive();
+ }
+
+// --------------------------------------------------------------------------
+// Event ready in window server event queue
+// --------------------------------------------------------------------------
+void CAknCompaSrvWsEventHandler::RunL()
+ {
+ // Window server event queue read to purge it in case wsrv sends
+ // something. As we dont have window group created this is probably
+ // unneccesary as there seem to be no events.
+ TWsEvent wsEvent;
+ iWsSession.GetEvent(wsEvent);
+ IssueRequest();
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaSrvWsEventHandler::DoCancel()
+ {
+ iWsSession.EventReadyCancel();
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaServer::CAknCompaServer()
+ :CServer2(CActive::EPriorityStandard)
+ {
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaServer::~CAknCompaServer()
+ {
+ delete iThemesCenRep;
+ delete iAvkonCenRep;
+
+ delete iWsEventHandler;
+ iWsSession.Close();
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CServer2* CAknCompaServer::NewLC()
+ {
+ CAknCompaServer* self = new (ELeave) CAknCompaServer;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaServer::ConstructL()
+ {
+ User::LeaveIfError(iWsSession.Connect());
+ iThemesCenRep = CRepository::NewL(KCRUidThemes);
+ iAvkonCenRep = CRepository::NewL(KCRUidAvkon);
+
+ // Check if compa-mode has disabled effects in repository
+ TInt savedEffects = KAknCompaModeEffectsDisabled;
+ iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects);
+ iEffectsDisabled = (savedEffects & KAknCompaModeEffectsSaved) != 0;
+
+ iWsEventHandler = new (ELeave) CAknCompaSrvWsEventHandler(iWsSession);
+ StartL(KAknCompaSrvName);
+ }
+
+// --------------------------------------------------------------------------
+// New session added to server
+// --------------------------------------------------------------------------
+void CAknCompaServer::AddSession()
+ {
+ iSessionCount++;
+ }
+
+
+// --------------------------------------------------------------------------
+// Session is closing
+// --------------------------------------------------------------------------
+void CAknCompaServer::DropSession()
+ {
+ if (--iSessionCount == 0)
+ {
+ // Stops the active scheduler. As this server runs in its
+ // own process this stop effectively kills the process
+ CActiveScheduler::Stop();
+ }
+ }
+
+// --------------------------------------------------------------------------
+// Get window server session
+// --------------------------------------------------------------------------
+RWsSession& CAknCompaServer::WsSession()
+ {
+ return iWsSession;
+ }
+
+// --------------------------------------------------------------------------
+// Create a new session
+// --------------------------------------------------------------------------
+CSession2* CAknCompaServer::NewSessionL(const TVersion& aVersion,
+ const RMessage2& /*aMessage*/) const
+ {
+ // Check that the version is OK
+ TVersion v(KAknCompaSrvMajorVersionNumber,
+ KAknCompaSrvMinorVersionNumber, KAknCompaSrvBuildVersionNumber);
+ if (!User::QueryVersionSupported(v,aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ return new (ELeave) CAknCompaSrvSession;
+ }
+
+// --------------------------------------------------------------------------
+// Panic server
+// --------------------------------------------------------------------------
+void CAknCompaServer::PanicServer(TAknCompaServerPanic aPanic)
+ {
+ User::Panic(KAknCompaSrvName, aPanic);
+ }
+
+// --------------------------------------------------------------------------
+// Panic client
+// --------------------------------------------------------------------------
+void CAknCompaServer::PanicClient(const RMessage2& aMessage,
+ TInt aPanic)
+ {
+ aMessage.Panic(KAknCompaSrvName, aPanic);
+ }
+
+// --------------------------------------------------------------------------
+// Check if process is a server that displays global
+// notes/notifications (Eikon server, Avkon notify and cap servers)
+// --------------------------------------------------------------------------
+TBool CAknCompaServer::IsGlobalUiSrv(const RMessage2& aMessage)
+ {
+ const TUint32 KEikSrvUid = 0x10003a4a;
+ return aMessage.SecureId().iId == KAknCapServerUid.iUid ||
+ aMessage.SecureId().iId == KCommonNotifierAppSrvUid.iUid ||
+ aMessage.SecureId().iId == KEikSrvUid;
+ }
+
+// --------------------------------------------------------------------------
+// Set thread priority to normal
+// --------------------------------------------------------------------------
+void CAknCompaServer::SetThreadPriorityNormal(TAny* /*aUnused*/)
+ {
+ RThread thread;
+ thread.SetPriority(EPriorityNormal);
+ }
+
+// --------------------------------------------------------------------------
+// Set thread priority higher than any non-signed application threads
+// --------------------------------------------------------------------------
+void CAknCompaServer::SetThreadPriorityHigh()
+ {
+ RThread thread;
+ thread.SetPriority(EPriorityAbsoluteRealTime1);
+ }
+
+// --------------------------------------------------------------------------
+// Disable transition effects
+// --------------------------------------------------------------------------
+void CAknCompaServer::DisaTransEffectsL(const RMessage2& aMessage)
+ {
+ if (!iEffectsDisabled)
+ {
+ // Allow effects control only from global ui servers
+ if (!IsGlobalUiSrv(aMessage))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+ iEffectsDisabled = ETrue;
+ // The only way to disable transition effects is through CenRep. The
+ // same variable is also controlled by "Control Panel". If the device
+ // is turned off while we have disabled effects, we need to enable
+ // them when device is restarted.
+ TInt savedEffects = KAknCompaModeEffectsDisabled;
+ iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects);
+
+ if ((savedEffects & KAknCompaModeEffectsSaved) == 0)
+ {
+ TInt effects = 0;
+ iThemesCenRep->Get(KThemesTransitionEffects, effects);
+ if (effects != KAknCompaModeEffectsDisabled)
+ {
+ iAvkonCenRep->Set(KAknCompaModeEffects,
+ effects | KAknCompaModeEffectsSaved);
+ iThemesCenRep->Set(KThemesTransitionEffects,
+ KAknCompaModeEffectsDisabled);
+ }
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// Restore transition effects to a state before they were disabled
+// --------------------------------------------------------------------------
+void CAknCompaServer::RestoreTransEffectsL(const RMessage2& aMessage)
+ {
+ if (iEffectsDisabled)
+ {
+ // Allow effects control only from global ui servers
+ if (!IsGlobalUiSrv(aMessage))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+ iEffectsDisabled = EFalse;
+
+ // Read saved effects state from our CenRep
+ TInt savedEffects = 0;
+ iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects);
+
+ if (savedEffects & KAknCompaModeEffectsSaved)
+ {
+ savedEffects &= ~KAknCompaModeEffectsSaved;
+ iThemesCenRep->Set(KThemesTransitionEffects, savedEffects);
+ iAvkonCenRep->Set(KAknCompaModeEffects, savedEffects);
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaServer& CAknCompaSrvSession::Server()
+ {
+ return *static_cast<CAknCompaServer*>
+ (const_cast<CServer2*>(CSession2::Server()));
+ }
+
+// --------------------------------------------------------------------------
+// Create session
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::CreateL()
+ {
+ // Allocate memory for keystate array to hold all possible keys.
+ // This avoid possibility of memory allocation error when key is
+ // added to key state array due to key press while application is
+ // executing.
+ iKeyState.Reserve(EKeyStateGranularity);
+
+ Server().AddSession();
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaSrvSession::CAknCompaSrvSession():
+ iKeyState(EKeyStateGranularity)
+ {
+ // We allow only rocker keys, softkeys and numeric keypad keys to be
+ // simulated.
+ static const TUint8 ValidScanCodes[] =
+ {
+ EStdKeyDevice0, EStdKeyUpArrow, EStdKeyDevice1, EStdKeyLeftArrow,
+ EStdKeyDevice3, EStdKeyRightArrow, EStdKeyRightShift,
+ EStdKeyDownArrow, EStdKeyBackspace, EStdKeyNkpAsterisk, EStdKeyHash,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39
+ };
+ iValidScanCodes.Set(ValidScanCodes, sizeof(ValidScanCodes));
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+CAknCompaSrvSession::~CAknCompaSrvSession()
+ {
+ TInt num = iKeyState.Count();
+
+ // When session closes, send key up events for all keys being in down
+ // state. This ensures even if application crashes that no keys are left
+ // down.
+ for( TInt i=0; i < num; i++)
+ {
+ SimulateKeyEvent(iKeyState[i], EFalse);
+ }
+ Server().DropSession();
+ iKeyState.Close();
+ }
+
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::ServiceL(const RMessage2& aMessage)
+ {
+ TRAPD(err, DispatchMessageL(aMessage));
+ aMessage.Complete(err);
+ }
+
+// --------------------------------------------------------------------------
+//
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::DispatchMessageL(const RMessage2& aMessage)
+ {
+ switch(aMessage.Function())
+ {
+ case ECompaSrvSimulateKeyEvent:
+ SimulateKeyEventServiceL(aMessage);
+ break;
+ case ECompaSrvDisaTransEffects:
+ Server().DisaTransEffectsL(aMessage);
+ break;
+ case ECompaSrvRestoreTransEffects:
+ Server().RestoreTransEffectsL(aMessage);
+ break;
+ // Requests that we don't understand at all are a different matter.
+ // This is considered a client programming error, so we panic the
+ // client - this also completes the message.
+ default:
+ CAknCompaServer::PanicClient(aMessage, EBadRequest);
+ }
+ }
+
+// --------------------------------------------------------------------------
+// Simulate key event for client application
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::SimulateKeyEventServiceL(const RMessage2& aMessage)
+ {
+ TInt scancode = aMessage.Int0();
+ TBool keyDown = aMessage.Int1();
+
+ // Check that scan code is valid. Client request will fail with error
+ // code KErrNotFound if the check fails.
+ TChar ch(scancode);
+ User::LeaveIfError(iValidScanCodes.Locate(ch));
+
+ if (keyDown)
+ {
+ // Set thread priority to very high. The purpose is to prevent
+ // other threads to change foreground application in between
+ // client foreground status check and SimulateRawEvent().
+ CAknCompaServer::SetThreadPriorityHigh();
+ CleanupStack::PushL(
+ TCleanupItem(CAknCompaServer::SetThreadPriorityNormal, NULL));
+ // Check that client task is foreground
+ CheckKeyDownPermissionL(aMessage);
+ }
+
+ // Keeps tracks which scancodes are in down state
+ if (keyDown)
+ {
+ // There can be only one of each scancode in the list
+ if (iKeyState.Find(scancode) == KErrNotFound)
+ {
+ iKeyState.AppendL(scancode);
+ SimulateKeyEvent(scancode, keyDown);
+ }
+ CleanupStack::PopAndDestroy();
+ }
+ else
+ {
+ TInt pos = iKeyState.Find(scancode);
+ if (pos != KErrNotFound)
+ {
+ iKeyState.Remove(pos);
+ iKeyState.GranularCompress();
+ SimulateKeyEvent(scancode, keyDown);
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// Simulate key event to window server
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::SimulateKeyEvent(TInt aScancode, TBool aKeyDown)
+ {
+ TRawEvent event;
+ event.Set(
+ aKeyDown ? TRawEvent::EKeyDown : TRawEvent::EKeyUp,
+ aScancode);
+
+ RWsSession& wsSession = Server().WsSession();
+ // Simulate key event as it came from a keypad
+ wsSession.SimulateRawEvent(event);
+ wsSession.Flush();
+ }
+
+// --------------------------------------------------------------------------
+// Check whether client key event request can be executed
+// --------------------------------------------------------------------------
+void CAknCompaSrvSession::CheckKeyDownPermissionL(const RMessage2& aMessage)
+ {
+ // We try to increase security by allowing only foreground application
+ // to set key down. As the simulated key events are sent to the
+ // foreground application by window server, the application is
+ // sending a key event to itself.
+
+ // Granted if client has ECapabilitySwEvent or request is coming from
+ // EikSrv. TApaTaskList won't report EikSrv in foreground though
+ // it's displaying a note.
+ if (!aMessage.HasCapability(ECapabilitySwEvent) &&
+ !CAknCompaServer::IsGlobalUiSrv(aMessage))
+ {
+ // Allow key down only from a foreground task
+ TApaTaskList tasklist(Server().WsSession());
+ TApaTask foregroundTask = tasklist.FindByPos(0);
+
+ RThread thread;
+ User::LeaveIfError(thread.Open(foregroundTask.ThreadId()));
+ TSecurityPolicy securityPolicy(thread.SecureId());
+ thread.Close();
+
+ if (!securityPolicy.CheckPolicy(aMessage))
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+ }
+ }