camerauis/cameraxui/cxui/src/cxuiapplicationframeworkmonitorprivate.cpp
branchRCL_3
changeset 54 bac7acad7cb3
parent 53 61bc0f252b2b
child 57 2c87b2808fd7
equal deleted inserted replaced
53:61bc0f252b2b 54:bac7acad7cb3
     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 #include <UsbWatcherInternalPSKeys.h> // usb status
       
    29 #include <usbman.h>
       
    30 #include <usbpersonalityids.h>
       
    31 
       
    32 #include <QMetaEnum>
       
    33 #include <QString>
       
    34 #include <QVariant>
       
    35 #include <QTimer>
       
    36 #include <qsymbianevent.h>
       
    37 
       
    38 #endif // Q_OS_SYMBIAN
       
    39 
       
    40 #include "cxutils.h"
       
    41 #include "cxuieventlog.h"
       
    42 #include "cxuiapplication.h"
       
    43 #include "cxesettings.h"
       
    44 #include "cxuiapplicationframeworkmonitorprivate.h"
       
    45 
       
    46 namespace{
       
    47     const int CXUI_USB_MODE_CHECK_TIMER_DELAY = 1000; // 1 second
       
    48 }
       
    49 
       
    50 #ifdef Q_OS_SYMBIAN
       
    51 namespace
       
    52 {
       
    53     inline QString convertTDesC2QString(const TDesC& aDescriptor)
       
    54     {
       
    55         #ifdef QT_NO_UNICODE
       
    56             return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length());
       
    57         #else
       
    58             return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length());
       
    59         #endif
       
    60     }
       
    61 
       
    62     inline QString windowGroupName(RWsSession& ws, int id)
       
    63     {
       
    64         TBuf<CApaWindowGroupName::EMaxLength> name;
       
    65         ws.GetWindowGroupNameFromIdentifier(id, name);
       
    66         // Window group name contains "null" characters,
       
    67         // which are considered end-of-string if not replaced.
       
    68         for (int i=0; i < name.Length(); i++) {
       
    69             if (name[i] == NULL) {
       
    70                 name[i] = ' ';
       
    71             }
       
    72         }
       
    73         return convertTDesC2QString(name);
       
    74     }
       
    75 
       
    76     inline QString bitString(int number, char fill = '0', int width = 32)
       
    77     {
       
    78         return QString::number(number, 2).rightJustified(width, fill);
       
    79     }
       
    80 
       
    81     //!@todo: Avkon UIDs not needed once device dialogs fully implemented in Orbit.
       
    82 
       
    83     // AknCapServer
       
    84     static const unsigned int UID_AKNCAPSERVER    = 0x10207218;
       
    85 
       
    86     // Phone ui
       
    87     static const unsigned int UID_PHONEUI         = 0x100058B3;
       
    88     // Task switcher
       
    89     static const unsigned int UID_TASKSWITCHER    = 0x2002677D;
       
    90     // Dialog server
       
    91     static const unsigned int UID_DIALOGAPPSERVER = 0x20022FC5;
       
    92 
       
    93     // Log event types
       
    94     static const char *EVENT_USB        = "usb";
       
    95     static const char *EVENT_FOREGROUND = "foreground";
       
    96 }
       
    97 #endif // Q_OS_SYMBIAN
       
    98 
       
    99 
       
   100 /*!
       
   101 * Constructor
       
   102 */
       
   103 CxuiApplicationFrameworkMonitorPrivate::CxuiApplicationFrameworkMonitorPrivate(CxuiApplicationFrameworkMonitor *parent,
       
   104                                                                                CxuiApplication &application,
       
   105                                                                                CxeSettings& settings)
       
   106     :  q(parent),
       
   107        mApplication(application),
       
   108        mSettings(settings),
       
   109 #ifdef Q_OS_SYMBIAN
       
   110        mWsSession(CCoeEnv::Static()->WsSession()),
       
   111        mWindowGroup(CCoeEnv::Static()->RootWin()),
       
   112        mWindowGroupId(mWindowGroup.Identifier()),
       
   113        mWindowGroupName(),
       
   114        mKeyLockState(EKeyguardNotActive),
       
   115        mBatteryStatus(EBatteryStatusUnknown),
       
   116        mUsbPersonality(0),
       
   117        mUsbModeCheckTimer(this),
       
   118        mEventLog(NULL),
       
   119 #endif // Q_OS_SYMBIAN
       
   120        mState(CxuiApplicationFrameworkMonitor::ForegroundOwned)
       
   121 {
       
   122     CX_DEBUG_ENTER_FUNCTION();
       
   123 #ifdef Q_OS_SYMBIAN
       
   124     mWindowGroup.EnableFocusChangeEvents();
       
   125     mWindowGroupName = windowGroupName(mWsSession, mWindowGroupId);
       
   126     mEventLog = new CxuiEventLog("CxuiApplicationFrameworkMonitorPrivate");
       
   127     init();
       
   128     mUsbModeCheckTimer.setSingleShot(true);
       
   129     mUsbModeCheckTimer.setInterval(CXUI_USB_MODE_CHECK_TIMER_DELAY);
       
   130     connect(&mUsbModeCheckTimer, SIGNAL(timeout()),
       
   131             this, SLOT(usbModeCheckTimerCallback()));
       
   132 #endif // Q_OS_SYMBIAN
       
   133     CX_DEBUG_EXIT_FUNCTION();
       
   134 }
       
   135 
       
   136 /*!
       
   137 * Destructor
       
   138 */
       
   139 CxuiApplicationFrameworkMonitorPrivate::~CxuiApplicationFrameworkMonitorPrivate()
       
   140 {
       
   141     CX_DEBUG_ENTER_FUNCTION();
       
   142 #ifdef Q_OS_SYMBIAN
       
   143     delete mEventLog;
       
   144 #endif // Q_OS_SYMBIAN
       
   145     CX_DEBUG_EXIT_FUNCTION();
       
   146 }
       
   147 
       
   148 /*!
       
   149 * Current foreground owning state of this application.
       
   150 * @return Foreground owning state.
       
   151 */
       
   152 CxuiApplicationFrameworkMonitor::ForegroundState CxuiApplicationFrameworkMonitorPrivate::foregroundState() const
       
   153 {
       
   154     return mState;
       
   155 }
       
   156 
       
   157 /*!
       
   158 * Is USB connected in mass memory mode?
       
   159 * @return True if USB mass memory mode is active and connected, false otherwise.
       
   160 */
       
   161 bool CxuiApplicationFrameworkMonitorPrivate::isUsbMassMemoryModeActive() const
       
   162 {
       
   163     bool active(false);
       
   164 #ifdef Q_OS_SYMBIAN
       
   165     // Mass memory mode activity can be seen from the KUsbWatcherSelectedPersonality property.
       
   166     // When USB is connected in Mass Memory Mode, we get KUsbPersonalityIdMS as personality id.
       
   167     // If USB is not connected, personality id is KUsbWatcherSelectedPersonalityNone.
       
   168     active = (mUsbPersonality == KUsbPersonalityIdMS);
       
   169 #endif // Q_OS_SYMBIAN
       
   170     return active;
       
   171 }
       
   172 
       
   173 
       
   174 
       
   175 #ifdef Q_OS_SYMBIAN
       
   176 /*!
       
   177 * Slot to handle Symbian event.
       
   178 * @param event Symbian event to be handled. (Ownership not taken.)
       
   179 */
       
   180 void CxuiApplicationFrameworkMonitorPrivate::handleEvent(const QSymbianEvent *event)
       
   181 {
       
   182     // We receive tons of these events, so function start and end traces
       
   183     // are intentionally left out.
       
   184 
       
   185     if (event) {
       
   186         switch (event->type()) {
       
   187         case QSymbianEvent::WindowServerEvent:
       
   188             handleWindowServerEvent(event);
       
   189             break;
       
   190         }
       
   191     }
       
   192 }
       
   193 
       
   194 /*!
       
   195 * Handle changes in RProperty values of keylock state and battery status.
       
   196 * @param uid Category uid of the changed property.
       
   197 * @param key Integer key of the changed property.
       
   198 * @param value New value of the changed property.
       
   199 */
       
   200 void CxuiApplicationFrameworkMonitorPrivate::handlePropertyEvent(long int uid, unsigned long int key, QVariant value)
       
   201 {
       
   202     CX_DEBUG_ENTER_FUNCTION();
       
   203 
       
   204     if (uid == KPSUidAvkonDomain.iUid && key == KAknKeyguardStatus) {
       
   205         CX_DEBUG(("CxuiApplicationFrameworkMonitor - keylock status changed: %d -> %d", mKeyLockState, value.toInt()));
       
   206 
       
   207         // Check if the keylock value has actually changed
       
   208         const int newKeyLockState = value.toInt();
       
   209         if (newKeyLockState != mKeyLockState) {
       
   210             mKeyLockState = newKeyLockState;
       
   211             // Set foreground state based on keylock status and focused application info.
       
   212             setState(getCurrentState());
       
   213         }
       
   214     } else if (uid == KPSUidHWRMPowerState.iUid && key == KHWRMBatteryStatus ) {
       
   215         CX_DEBUG(("CxuiApplicationFrameworkMonitor - battery status changed: %d -> %d", mBatteryStatus, value.toInt() ));
       
   216 
       
   217         // If status changed, check if battery is going empty.
       
   218         const int newBatteryStatus = value.toInt();
       
   219         if (newBatteryStatus != mBatteryStatus) {
       
   220             mBatteryStatus = newBatteryStatus;
       
   221 
       
   222             // Notify that battery is almost empty,
       
   223             // need to stop any recordings etc.
       
   224             if(mBatteryStatus == EBatteryStatusEmpty) {
       
   225                 emit q->batteryEmpty();
       
   226             }
       
   227         }
       
   228     } else if (uid == KPSUidUsbWatcher.iUid && key == KUsbWatcherSelectedPersonality) {
       
   229         CX_DEBUG(("CxuiApplicationFrameworkMonitor - usb personality changed: %d -> %d", mUsbPersonality, value.toInt()));
       
   230 
       
   231         const int newUsbPersonality(value.toInt());
       
   232         if (newUsbPersonality != mUsbPersonality) {
       
   233             // Check before saving the new state if mass memory mode was active,
       
   234             // so we know when to emit the unactivated signal.
       
   235             const bool wasUsbMassMemoryModeActive(isUsbMassMemoryModeActive());
       
   236             // Store new state.
       
   237             mUsbPersonality = newUsbPersonality;
       
   238 
       
   239             // Save state to log.
       
   240             if (mEventLog) {
       
   241                 mEventLog->append(EVENT_USB, QString::number(mUsbPersonality));
       
   242             }
       
   243 
       
   244             // Check if mass memory mode activity changed.
       
   245             if (wasUsbMassMemoryModeActive != isUsbMassMemoryModeActive()) {
       
   246 
       
   247                 // If the massmemory mode switched from on to off,
       
   248                 // the signal is emitted immediately.
       
   249                 // If the switch is from off to on, we need to use a timer
       
   250                 // as a workaround because  plugging in the USB charger
       
   251                 // sends a mass memory mode change event.
       
   252                 if (wasUsbMassMemoryModeActive) {
       
   253                     emit q->usbMassMemoryModeToggled(isUsbMassMemoryModeActive());
       
   254                 } else {
       
   255                     // (Re)starting the timer
       
   256                     mUsbModeCheckTimer.stop();
       
   257                     mUsbModeCheckTimer.start();
       
   258                 }
       
   259 
       
   260             }
       
   261         }
       
   262     }
       
   263 
       
   264     CX_DEBUG_EXIT_FUNCTION();
       
   265 }
       
   266 
       
   267 /*!
       
   268 *  Callback function for the timer used to seperate USB charging
       
   269 *  from USB mass memory mode
       
   270 */
       
   271 void CxuiApplicationFrameworkMonitorPrivate::usbModeCheckTimerCallback()
       
   272 {
       
   273     CX_DEBUG_ENTER_FUNCTION();
       
   274 
       
   275     // if the device is still in mass memory mode after the timer has finished,
       
   276     // the device really is in massmemory mode and not plugged into the charger
       
   277     if (isUsbMassMemoryModeActive()){
       
   278         emit q->usbMassMemoryModeToggled(isUsbMassMemoryModeActive());
       
   279     }
       
   280 
       
   281     CX_DEBUG_EXIT_FUNCTION();
       
   282 }
       
   283 
       
   284 /*!
       
   285 * Set initial values.
       
   286 */
       
   287 void CxuiApplicationFrameworkMonitorPrivate::init()
       
   288 {
       
   289     CX_DEBUG_ENTER_FUNCTION();
       
   290 
       
   291     // Connect to application (window server) events.
       
   292     connect(&mApplication, SIGNAL(symbianEvent(const QSymbianEvent *)), this, SLOT(handleEvent(const QSymbianEvent *)));
       
   293 
       
   294     QVariant value;
       
   295 
       
   296     // Get initial battery status.
       
   297     mSettings.get(KPSUidHWRMPowerState.iUid, KHWRMBatteryStatus, Cxe::PublishAndSubscribe, value);
       
   298     mBatteryStatus = value.toInt();
       
   299 
       
   300     // Get initial keylock status.
       
   301     mSettings.get(KPSUidAvkonDomain.iUid, KAknKeyguardStatus, Cxe::PublishAndSubscribe, value);
       
   302     mKeyLockState = value.toInt();
       
   303 
       
   304     // Get current USB personality
       
   305     mSettings.get(KPSUidUsbWatcher.iUid, KUsbWatcherSelectedPersonality, Cxe::PublishAndSubscribe, value);
       
   306     mUsbPersonality = value.toInt();
       
   307 
       
   308     bool ok = connect(&mSettings, SIGNAL(settingValueChanged(long int, unsigned long int, QVariant)),
       
   309                       this, SLOT(handlePropertyEvent(long int, unsigned long int, QVariant)));
       
   310     CX_DEBUG_ASSERT(ok);
       
   311 
       
   312     // Get foreground state. Depends on keyguard status, so that needs to be read first.
       
   313     mState = getCurrentState();
       
   314 
       
   315     CX_DEBUG_EXIT_FUNCTION();
       
   316 }
       
   317 
       
   318 /*!
       
   319 * Helper method to handle Symbian event that specificly is of type QSymbianEvent::WindowServerEvent.
       
   320 * @param event Symbian event to be handled. (Ownership not taken.)
       
   321 */
       
   322 void CxuiApplicationFrameworkMonitorPrivate::handleWindowServerEvent(const QSymbianEvent *event)
       
   323     {
       
   324     // We receive tons of these events, so function start and end traces
       
   325     // are intentionally left out.
       
   326 
       
   327     const TWsEvent *wsEvent = event->windowServerEvent();
       
   328     if (wsEvent) {
       
   329         switch (wsEvent->Type()) {
       
   330         case EEventFocusGroupChanged: {
       
   331             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusGroupChanged event"));
       
   332             setState(getCurrentState());
       
   333             break;
       
   334         }
       
   335         case EEventFocusGained: {
       
   336             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusGained event"));
       
   337             setState(getCurrentState());
       
   338             break;
       
   339         }
       
   340         case EEventFocusLost: {
       
   341             CX_DEBUG(("CxuiApplicationFrameworkMonitor - EEventFocusLost event"));
       
   342             setState(getCurrentState());
       
   343             break;
       
   344         }
       
   345         case EEventWindowVisibilityChanged: {
       
   346             const TWsVisibilityChangedEvent *visibilityEvent = wsEvent->VisibilityChanged();
       
   347             if (visibilityEvent) {
       
   348                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - EFullyVisible: bits[%s]",
       
   349                     bitString(TWsVisibilityChangedEvent::EFullyVisible).toAscii().constData() ));
       
   350                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - EPartiallyVisible: bits[%s]",
       
   351                     bitString(TWsVisibilityChangedEvent::EPartiallyVisible).toAscii().constData() ));
       
   352                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - ENotVisible: bits[%s]",
       
   353                     bitString(TWsVisibilityChangedEvent::ENotVisible).toAscii().constData() ));
       
   354                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - event:       bits[%s]",
       
   355                     bitString(visibilityEvent->iFlags).toAscii().constData() ));
       
   356             }
       
   357             break;
       
   358         }
       
   359         default:
       
   360             break;
       
   361         }
       
   362     }
       
   363 }
       
   364 
       
   365 /*!
       
   366 * Set state and emit signal if state really changes.
       
   367 * @param state New state.
       
   368 */
       
   369 void CxuiApplicationFrameworkMonitorPrivate::setState(CxuiApplicationFrameworkMonitor::ForegroundState state)
       
   370 {
       
   371     if (mState != state) {
       
   372         const CxuiApplicationFrameworkMonitor::ForegroundState original(mState);
       
   373 
       
   374         // Check if state transition is acceptable in current state.
       
   375         switch (mState) {
       
   376         case CxuiApplicationFrameworkMonitor::ForegroundOwned:
       
   377         case CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost:
       
   378             // All changes accepted.
       
   379             mState = state;
       
   380             break;
       
   381         case CxuiApplicationFrameworkMonitor::ForegroundFullyLost:
       
   382             // If foreground application is changed to note when we are already
       
   383             // fully in background, cannot accept state change to "partial foreground".
       
   384             if (state != CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost) {
       
   385                 mState = state;
       
   386             } else {
       
   387                 CX_DEBUG(("CxuiApplicationFrameworkMonitor - state change full bg -> partial bg ignored"));
       
   388             }
       
   389         }
       
   390 
       
   391         if (mState != original) {
       
   392             // Print the event log with this foreground event included.
       
   393             if (mEventLog) {
       
   394                 mEventLog->append(
       
   395                     EVENT_FOREGROUND,
       
   396                     CxuiApplicationFrameworkMonitor::staticMetaObject.enumerator(
       
   397                         CxuiApplicationFrameworkMonitor::staticMetaObject.indexOfEnumerator("ForegroundState")).valueToKey(mState));
       
   398                 mEventLog->print();
       
   399             }
       
   400 
       
   401             // If state was changed, signal it to listeners.
       
   402             emit q->foregroundStateChanged(mState);
       
   403         }
       
   404     }
       
   405 }
       
   406 
       
   407 /*!
       
   408 * Get the current foreground state.
       
   409 * @return Current state for foreground ownership.
       
   410 */
       
   411 CxuiApplicationFrameworkMonitor::ForegroundState CxuiApplicationFrameworkMonitorPrivate::getCurrentState()
       
   412 {
       
   413     CX_DEBUG_ENTER_FUNCTION();
       
   414 
       
   415     CxuiApplicationFrameworkMonitor::ForegroundState state(CxuiApplicationFrameworkMonitor::ForegroundOwned);
       
   416     int focusWindowGroupId(mWsSession.GetFocusWindowGroup());
       
   417 
       
   418     if (mKeyLockState != EKeyguardNotActive) {
       
   419         // Keylock enabled is the same as if other application is in foreground.
       
   420         CX_DEBUG(("CxuiApplicationFrameworkMonitor - key lock on"));
       
   421         state = CxuiApplicationFrameworkMonitor::ForegroundFullyLost;
       
   422     } else if (focusWindowGroupId == mWindowGroupId) {
       
   423         // If our window group has focus, we clearly are the foreground owning application.
       
   424         CX_DEBUG(("CxuiApplicationFrameworkMonitor - Foreground window group matches ours."));
       
   425         state = CxuiApplicationFrameworkMonitor::ForegroundOwned;
       
   426 
       
   427     } else {
       
   428         // Need to check if foreground is owned by known apps.
       
   429         unsigned int uid(focusedApplicationUid());
       
   430 
       
   431         // Check the app uid.
       
   432         switch (uid) {
       
   433         case UID_AKNCAPSERVER:
       
   434         case UID_TASKSWITCHER:
       
   435         case UID_DIALOGAPPSERVER:
       
   436             // Note or task switcher in foreground.
       
   437             state = CxuiApplicationFrameworkMonitor::ForegroundPartiallyLost;
       
   438             break;
       
   439         case UID_PHONEUI:
       
   440         default:
       
   441             // Foreground owned by other app.
       
   442             state = CxuiApplicationFrameworkMonitor::ForegroundFullyLost;
       
   443             break;
       
   444         }
       
   445     }
       
   446 
       
   447     CX_DEBUG_EXIT_FUNCTION();
       
   448     return state;
       
   449 }
       
   450 
       
   451 /*!
       
   452 * Get the uid of application in foreground.
       
   453 * @return Application uid for the foreground application.
       
   454 */
       
   455 unsigned int CxuiApplicationFrameworkMonitorPrivate::focusedApplicationUid()
       
   456 {
       
   457     unsigned int uid(0);
       
   458     int focusWgId(mWsSession.GetFocusWindowGroup());
       
   459 
       
   460     TRAP_IGNORE({
       
   461         CApaWindowGroupName* wgn = CApaWindowGroupName::NewLC(mWsSession, focusWgId);
       
   462         uid = wgn->AppUid().iUid;
       
   463         CleanupStack::PopAndDestroy(wgn);
       
   464     });
       
   465 
       
   466     // If the window group identifier does not have the application uid set,
       
   467     // get it via thread secure id.
       
   468     if (uid == 0) {
       
   469         TApaTask task(mWsSession);
       
   470         task.SetWgId(focusWgId);
       
   471 
       
   472         RThread t;
       
   473         int err = t.Open(task.ThreadId());
       
   474         if (err == KErrNone) {
       
   475             uid = t.SecureId().iId;
       
   476             CX_DEBUG(("CxuiApplicationFrameworkMonitor - uid resolved from thread"));
       
   477         }
       
   478         t.Close();
       
   479     }
       
   480 
       
   481 #ifdef CX_DEBUG
       
   482     QString name(windowGroupName(mWsSession, focusWgId));
       
   483     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Own window group id:     0x%08x", mWindowGroupId));
       
   484     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused window group id: 0x%08x", focusWgId));
       
   485     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Own window group name:        [%s]", mWindowGroupName.toAscii().constData()));
       
   486     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused window group name:    [%s]", name.toAscii().constData()));
       
   487     CX_DEBUG(("CxuiApplicationFrameworkMonitor - Focused application uid: 0x%08x", uid));
       
   488 #endif
       
   489 
       
   490     return uid;
       
   491 }
       
   492 
       
   493 #endif // Q_OS_SYMBIAN
       
   494 
       
   495 // end of file