camerauis/cameraxui/cxui/src/cxuiapplicationframeworkmonitorprivate.cpp
changeset 28 3075d9b614e6
child 36 b12f3922a74f
equal deleted inserted replaced
19:d9aefe59d544 28:3075d9b614e6
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QObject>
       
    19 
       
    20 #ifdef Q_OS_SYMBIAN
       
    21 #include <e32cmn.h>
       
    22 #include <w32std.h>
       
    23 #include <apgwgnam.h>
       
    24 #include <apgtask.h>
       
    25 #include <eikenv.h>
       
    26 #include <avkondomainpskeys.h>  // keyguard state
       
    27 #include <hwrmpowerstatesdkpskeys.h> // battery status
       
    28 
       
    29 #include <QMetaEnum>
       
    30 #include <QString>
       
    31 #include <QVariant>
       
    32 #include <qsymbianevent.h>
       
    33 #endif // Q_OS_SYMBIAN
       
    34 
       
    35 #include "cxutils.h"
       
    36 #include "cxuiapplication.h"
       
    37 #include "cxesettings.h"
       
    38 #include "cxuiapplicationframeworkmonitorprivate.h"
       
    39 
       
    40 
       
    41 #ifdef Q_OS_SYMBIAN
       
    42 namespace
       
    43 {
       
    44     inline QString convertTDesC2QString(const TDesC& aDescriptor)
       
    45     {
       
    46         #ifdef QT_NO_UNICODE
       
    47             return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length());
       
    48         #else
       
    49             return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length());
       
    50         #endif
       
    51     }
       
    52 
       
    53     inline QString windowGroupName(RWsSession& ws, int id)
       
    54     {
       
    55         TBuf<CApaWindowGroupName::EMaxLength> name;
       
    56         ws.GetWindowGroupNameFromIdentifier(id, name);
       
    57         // Window group name contains "null" characters,
       
    58         // which are considered end-of-string if not replaced.
       
    59         for (int i=0; i < name.Length(); i++) {
       
    60             if (name[i] == NULL) {
       
    61                 name[i] = ' ';
       
    62             }
       
    63         }
       
    64         return convertTDesC2QString(name);
       
    65     }
       
    66 
       
    67     //!@todo: Avkon UIDs not needed once device dialogs fully implemented in Orbit.
       
    68 
       
    69     // AknCapServer
       
    70     static const unsigned int UID_AKNCAPSERVER    = 0x10207218;
       
    71 
       
    72     // Phone ui
       
    73     static const unsigned int UID_PHONEUI         = 0x100058B3;
       
    74     // Task switcher
       
    75     static const unsigned int UID_TASKSWITCHER    = 0x2002677D;
       
    76     // Dialog server
       
    77     static const unsigned int UID_DIALOGAPPSERVER = 0x20022FC5;
       
    78 }
       
    79 #endif // Q_OS_SYMBIAN
       
    80 
       
    81 
       
    82 /*!
       
    83 * Constructor
       
    84 */
       
    85 CxuiApplicationFrameworkMonitorPrivate::CxuiApplicationFrameworkMonitorPrivate(CxuiApplication &application, CxeSettings& settings)
       
    86     :  mApplication(application),
       
    87        mSettings(settings),
       
    88 #ifdef Q_OS_SYMBIAN
       
    89        mWsSession(CCoeEnv::Static()->WsSession()),
       
    90        mWindowGroup(CCoeEnv::Static()->RootWin()),
       
    91        mWindowGroupId(mWindowGroup.Identifier()),
       
    92        mWindowGroupName(),
       
    93        mKeyLockState(EKeyguardNotActive),
       
    94        mBatteryStatus(EBatteryStatusUnknown),
       
    95 #endif // Q_OS_SYMBIAN
       
    96        mState(CxuiApplicationFrameworkMonitor::ForegroundOwned)
       
    97 {
       
    98     CX_DEBUG_ENTER_FUNCTION();
       
    99 
       
   100 #ifdef Q_OS_SYMBIAN
       
   101     mWindowGroup.EnableFocusChangeEvents();
       
   102     mWindowGroupName = windowGroupName(mWsSession, mWindowGroupId);
       
   103     init();
       
   104 #endif // Q_OS_SYMBIAN
       
   105 
       
   106     CX_DEBUG_EXIT_FUNCTION();
       
   107 }
       
   108 
       
   109 /*!
       
   110 * Destructor
       
   111 */
       
   112 CxuiApplicationFrameworkMonitorPrivate::~CxuiApplicationFrameworkMonitorPrivate()
       
   113 {
       
   114     CX_DEBUG_IN_FUNCTION();
       
   115 }
       
   116 
       
   117 /*!
       
   118 * Current foreground owning state of this application.
       
   119 * @return Foreground owning state.
       
   120 */
       
   121 CxuiApplicationFrameworkMonitor::ForegroundState CxuiApplicationFrameworkMonitorPrivate::foregroundState() const
       
   122 {
       
   123     return mState;
       
   124 }
       
   125 
       
   126 #ifdef Q_OS_SYMBIAN
       
   127 /*!
       
   128 * Slot to handle Symbian event.
       
   129 * @param event Symbian event to be handled. (Ownership not taken.)
       
   130 */
       
   131 void CxuiApplicationFrameworkMonitorPrivate::handleEvent(const QSymbianEvent *event)
       
   132 {
       
   133     // We receive tons of these events, so function start and end traces
       
   134     // are intentionally left out.
       
   135 
       
   136     if (event) {
       
   137         switch (event->type()) {
       
   138         case QSymbianEvent::WindowServerEvent:
       
   139             handleWindowServerEvent(event);
       
   140             break;
       
   141         }
       
   142     }
       
   143 }
       
   144 
       
   145 /*!
       
   146 * Handle changes in RProperty values of keylock state and battery status.
       
   147 * @param uid Category uid of the changed property.
       
   148 * @param key Integer key of the changed property.
       
   149 * @param value New value of the changed property.
       
   150 */
       
   151 void CxuiApplicationFrameworkMonitorPrivate::handlePropertyEvent(long int uid, unsigned long int key, QVariant value)
       
   152 {
       
   153     CX_DEBUG_ENTER_FUNCTION();
       
   154 
       
   155     if (uid == KPSUidAvkonDomain.iUid && key == KAknKeyguardStatus) {
       
   156         CX_DEBUG(("CxuiApplicationFrameworkMonitor - keylock status changed: %d -> %d", value.toInt(), mKeyLockState));
       
   157 
       
   158         // Check if the keylock value has actually changed
       
   159         const int newKeyLockState = value.toInt();
       
   160         if (newKeyLockState != mKeyLockState) {
       
   161             mKeyLockState = newKeyLockState;
       
   162             // Set foreground state based on keylock status and focused application info.
       
   163             setState(getCurrentState());
       
   164         }
       
   165     } else if (uid == KPSUidHWRMPowerState.iUid && key == KHWRMBatteryStatus ) {
       
   166         CX_DEBUG(("CxuiApplicationFrameworkMonitor - battery status changed: %d -> %d", value.toInt(), mBatteryStatus));
       
   167 
       
   168         // If status changed, check if battery is going empty.
       
   169         const int newBatteryStatus = value.toInt();
       
   170         if (newBatteryStatus != mBatteryStatus) {
       
   171             mBatteryStatus = newBatteryStatus;
       
   172 
       
   173             // Notify that battery is almost empty,
       
   174             // need to stop any recordings etc.
       
   175             if( mBatteryStatus == EBatteryStatusEmpty ) {
       
   176                 emit batteryEmpty();
       
   177             }
       
   178         }
       
   179     }
       
   180 
       
   181     CX_DEBUG_EXIT_FUNCTION();
       
   182 }
       
   183 
       
   184 /*!
       
   185 * Set initial values.
       
   186 */
       
   187 void CxuiApplicationFrameworkMonitorPrivate::init()
       
   188 {
       
   189     CX_DEBUG_ENTER_FUNCTION();
       
   190 
       
   191     // Connect to application (window server) events.
       
   192     connect(&mApplication, SIGNAL(symbianEvent(const QSymbianEvent *)), this, SLOT(handleEvent(const QSymbianEvent *)));
       
   193 
       
   194     QVariant value;
       
   195 
       
   196     // Get initial battery status.
       
   197     mSettings.get(KPSUidHWRMPowerState.iUid, KHWRMBatteryStatus, Cxe::PublishAndSubscribe, value);
       
   198     mBatteryStatus = value.toInt();
       
   199 
       
   200     // Get initial keylock status.
       
   201     mSettings.get(KPSUidAvkonDomain.iUid, KAknKeyguardStatus, Cxe::PublishAndSubscribe, value);
       
   202     mKeyLockState = value.toInt();
       
   203 
       
   204     bool ok = connect(&mSettings, SIGNAL(settingValueChanged(long int, unsigned long int, QVariant)),
       
   205                       this, SLOT(handlePropertyEvent(long int, unsigned long int, QVariant)));
       
   206     CX_DEBUG_ASSERT(ok);
       
   207 
       
   208     // Get foreground state. Depends on keyguard status, so that needs to be read first.
       
   209     mState = getCurrentState();
       
   210 
       
   211     CX_DEBUG_EXIT_FUNCTION();
       
   212 }
       
   213 
       
   214 /*!
       
   215 * Helper method to handle Symbian event that specificly is of type QSymbianEvent::WindowServerEvent.
       
   216 * @param event Symbian event to be handled. (Ownership not taken.)
       
   217 */
       
   218 bool CxuiApplicationFrameworkMonitorPrivate::handleWindowServerEvent(const QSymbianEvent *event)
       
   219     {
       
   220     // We receive tons of these events, so function start and end traces
       
   221     // are intentionally left out.
       
   222 
       
   223     const TWsEvent *wsEvent = event->windowServerEvent();
       
   224     if (wsEvent) {
       
   225         switch (wsEvent->Type()) {
       
   226         case EEventFocusGroupChanged: {
       
   227             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusGroupChanged event"));
       
   228             setState(getCurrentState());
       
   229             break;
       
   230         }
       
   231         case EEventFocusGained: {
       
   232             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusGained event"));
       
   233             setState(getCurrentState());
       
   234             break;
       
   235         }
       
   236         case EEventFocusLost: {
       
   237             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusLost event"));
       
   238             setState(getCurrentState());
       
   239             break;
       
   240         }
       
   241         case EEventWindowVisibilityChanged: {
       
   242             const TWsVisibilityChangedEvent *visibilityEvent = wsEvent->VisibilityChanged();
       
   243             if (visibilityEvent) {
       
   244                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - EFullyVisible: bits[%s]",
       
   245                     QString::number(TWsVisibilityChangedEvent::EFullyVisible, 2).toAscii().constData() ));
       
   246                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - EPartiallyVisible: bits[%s]",
       
   247                     QString::number(TWsVisibilityChangedEvent::EPartiallyVisible, 2).toAscii().constData() ));
       
   248                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - ENotVisible: bits[%s]",
       
   249                     QString::number(TWsVisibilityChangedEvent::ENotVisible, 2).toAscii().constData() ));
       
   250                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - event:       bits[%s]",
       
   251                     QString::number(visibilityEvent->iFlags, 2).toAscii().constData() ));
       
   252             }
       
   253             break;
       
   254         }
       
   255         default:
       
   256             break;
       
   257         }
       
   258     }
       
   259 
       
   260     return false;
       
   261 }
       
   262 
       
   263 /*!
       
   264 * Set state and emit signal if state really changes.
       
   265 * @param state New state.
       
   266 */
       
   267 void CxuiApplicationFrameworkMonitorPrivate::setState(CxuiApplicationFrameworkMonitor::ForegroundState state)
       
   268 {
       
   269     if (mState != state) {
       
   270         const CxuiApplicationFrameworkMonitor::ForegroundState original(mState);
       
   271 
       
   272         // Check if state transition is acceptable in current state.
       
   273         switch (mState) {
       
   274         case CxuiApplicationFrameworkMonitor::ForegroundOwned:
       
   275         case CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost:
       
   276             // All changes accepted.
       
   277             mState = state;
       
   278             break;
       
   279         case CxuiApplicationFrameworkMonitor::ForegroundFullyLost:
       
   280             // If foreground application is changed to note when we are already
       
   281             // fully in background, cannot accept state change to "partial foreground".
       
   282             if (state != CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost) {
       
   283                 mState = state;
       
   284             } else {
       
   285                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - state change full bg -> partial bg ignored"));
       
   286             }
       
   287         }
       
   288 
       
   289         if (mState != original) {
       
   290             CX_DEBUG(("CxuiApplicationFrameworkMonitor - state change [%s] -> [%s]",
       
   291                 CxuiApplicationFrameworkMonitor::staticMetaObject.enumerator(
       
   292                     CxuiApplicationFrameworkMonitor::staticMetaObject.indexOfEnumerator("ForegroundState")).valueToKey(original),
       
   293                 CxuiApplicationFrameworkMonitor::staticMetaObject.enumerator(
       
   294                     CxuiApplicationFrameworkMonitor::staticMetaObject.indexOfEnumerator("ForegroundState")).valueToKey(mState) ));
       
   295 
       
   296             // If state was changed, signal it to listeners.
       
   297             emit foregroundStateChanged(mState);
       
   298         }
       
   299     }
       
   300 }
       
   301 
       
   302 /*!
       
   303 * Get the current foreground state.
       
   304 * @return Current state for foreground ownership.
       
   305 */
       
   306 CxuiApplicationFrameworkMonitor::ForegroundState CxuiApplicationFrameworkMonitorPrivate::getCurrentState()
       
   307 {
       
   308     CX_DEBUG_ENTER_FUNCTION();
       
   309 
       
   310     CxuiApplicationFrameworkMonitor::ForegroundState state(CxuiApplicationFrameworkMonitor::ForegroundOwned);
       
   311     int focusWindowGroupId(mWsSession.GetFocusWindowGroup());
       
   312 
       
   313     if (mKeyLockState != EKeyguardNotActive) {
       
   314         // Keylock enabled is the same as if other application is in foreground.
       
   315         state = CxuiApplicationFrameworkMonitor::ForegroundFullyLost;
       
   316     } else if (focusWindowGroupId == mWindowGroupId) {
       
   317         // If our window group has focus, we clearly are the foreground owning application.
       
   318         CX_DEBUG(("CxuiApplicationFrameworkMonitor - Foreground window group matches ours."));
       
   319         state = CxuiApplicationFrameworkMonitor::ForegroundOwned;
       
   320 
       
   321     } else {
       
   322         // Need to check if foreground is owned by known apps.
       
   323         unsigned int uid(focusedApplicationUid());
       
   324 
       
   325         // Check the app uid.
       
   326         switch (uid) {
       
   327         case UID_AKNCAPSERVER:
       
   328         case UID_TASKSWITCHER:
       
   329         case UID_DIALOGAPPSERVER:
       
   330             // Note or task switcher in foreground.
       
   331             state = CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost;
       
   332             break;
       
   333         case UID_PHONEUI:
       
   334         default:
       
   335             // Foreground owned by other app.
       
   336             state = CxuiApplicationFrameworkMonitor::ForegroundFullyLost;
       
   337             break;
       
   338         }
       
   339     }
       
   340 
       
   341     CX_DEBUG_EXIT_FUNCTION();
       
   342     return state;
       
   343 }
       
   344 
       
   345 /*!
       
   346 * Get the uid of application in foreground.
       
   347 * @return Application uid for the foreground application.
       
   348 */
       
   349 unsigned int CxuiApplicationFrameworkMonitorPrivate::focusedApplicationUid()
       
   350 {
       
   351     unsigned int uid(0);
       
   352     int focusWgId(mWsSession.GetFocusWindowGroup());
       
   353 
       
   354     TRAP_IGNORE({
       
   355         CApaWindowGroupName* wgn = CApaWindowGroupName::NewLC(mWsSession, focusWgId);
       
   356         uid = wgn->AppUid().iUid;
       
   357         CleanupStack::PopAndDestroy(wgn);
       
   358     });
       
   359 
       
   360     // If the window group identifier does not have the application uid set,
       
   361     // get it via thread secure id.
       
   362     if (uid == 0) {
       
   363         TApaTask task(mWsSession);
       
   364         task.SetWgId(focusWgId);
       
   365 
       
   366         RThread t;
       
   367         int err = t.Open(task.ThreadId());
       
   368         if (err == KErrNone) {
       
   369             uid = t.SecureId().iId;
       
   370             CX_DEBUG(("CxuiApplicationFrameworkMonitor - uid resolved from thread"));
       
   371         }
       
   372         t.Close();
       
   373     }
       
   374 
       
   375 #ifdef CX_DEBUG
       
   376     QString name(windowGroupName(mWsSession, focusWgId));
       
   377 
       
   378     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Own window group id:     0x%08x", mWindowGroupId));
       
   379     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused window group id: 0x%08x", focusWgId));
       
   380     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Own window group name:        [%s]", mWindowGroupName.toAscii().constData()));
       
   381     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused window group name:    [%s]", name.toAscii().constData()));
       
   382     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused application uid: 0x%08x", uid));
       
   383 #endif
       
   384 
       
   385     return uid;
       
   386 }
       
   387 
       
   388 #endif // Q_OS_SYMBIAN
       
   389 
       
   390 // end of file