首 页 | 新 闻 | Symbian | Android| Windows Mobile | J2ME | 下载中心 | 游戏策划招聘与求职 | 购书指南 | 视频教程
您现在的位置: 开发视界 >> Symbian英文资料 >> User Interface >> 正文
Detecting user inactivity
作者:佚名    文章来源:不详    更新时间:2006-5-6 22:48:47

Detecting user inactivity in Symbian OS

Introduction

This article describes how to detect user activity and inactivity in Symbian OS. An active object is described, that can be used to detect user activity events. By user activity I mean any key presses or other activity the user performs with the phone, such as opening or closing the keypad on the 7650. User activity can also be simulated by applications with the system call:

User::ResetInactivityTime();

Several system applications simulate user activity. For example the phone application simulates user activity when there is an incoming call. This is because user activity causes the system screen saver to disappear and the back light to come on for example. System information notes might also call ResetInactivityTime(). You too can control system screen saver and system back light in your applications by calling ResetInactivityTime(). In addition, you can detect the number of user inactivity seconds at any time by calling:

User::InactivityTime();

However, to be notified when there has been a certain amount of seconds without user activity you need to use the call:

Rtimer::Inactivity(TRequestStatus& aStatus, TTimeIntervalSeconds aSeconds);

This call can be used to implement an active object that allows you to be notified when the has been a certain period of user inactivity. This is the basis for implementing applications such as screen savers or other applications that need to do some processing when there is no user activity.

In this article such an active object is described. This active object uses the observer paradigm as an interface towards the rest of the application. You can therefore implement the logic of your application in the observer callbacks. Detecting user inactivity is relatively straightforward. However not so detecting when user activity is resumed after an inactivity period. This is because there is no API to do that. Whilst one could be tempted to periodically call User::InactivityTime() this would cause a drain of battery life. This article therefore also describes a trick to detect user activity by abusing a little bit the semantics of the Rtimer::Inactivity() call.

Implementation

The active object monitoring user activity or inactivity uses an observer to communicate to the rest of the application. The declaration of the observer is as follows:

class MactivityManagerObserver

{
public :
    virtual void ActivityDetected() = 0;
virtual void InactivityDetected() = 0;

};

In InactivityDetected() you implement what your application needs to do when there has been inactivity, e.g. if you are writing a screen saver your application will come to the foreground. In ActivityDetected() you implement what your application needs to do when activity is resumed after the inactivity period, e.g. if you are writing a screen saver your application will go to the background.

This declaration of the active object is as follows:

class CActivityManager : public CActive

{

public:

IMPORT_C static CActivityManager* NewL(MActivityManagerObserver* aObserver, TInt aTimeout = 60);

IMPORT_C ~CActivityManager();

IMPORT_C void SetTimeout(TInt aTimeout);

IMPORT_C void Start();

IMPORT_C void Reset();

protected: // from CActive

void DoCancel();

void RunL();

protected:

CActivityManager(MActivityManagerObserver* aObserver, TInt aTimeout);

void ConstructL();

protected:

enum TWatch { ENone = 0, EWaitingForInactivity, EWaitingForActivity };

protected:

RTimer iTimer;

TWatch iWatch;

MActivityManagerObserver* iObserver; ///The observer of activity status

TInt iTimeout; ///Current inactivity period

};

You create an instance of this active object by calling NewL. You can change the timeout (in seconds) by calling SetTimeout(). This is the timeout after which, if there has been no user activity, InactivityDetected() is called in your observer. You start monitoring user activity by calling Start() and stop by calling Reset(). Calling SetTimeout() always causes a reset of inactivity monitoring.

As for the implementation, here are some trivial methods:

EXPORT_C CActivityManager* CActivityManager::NewL(MActivityManagerObserver* aObserver, TInt aTimeout)

{

CActivityManager* self = new (ELeave) CActivityManager(aObserver, aTimeout);

CleanupStack::PushL(self);

self->ConstructL();

CleanupStack::Pop(self);

return self;

}

CActivityManager::CActivityManager(MActivityManagerObserver* aObserver, TInt aTimeout)

: CActive(CActive::EPriorityHigh), iObserver(aObserver), iTimeout(aTimeout)

{

CActiveScheduler::Add(this);

}

EXPORT_C CActivityManager::~CActivityManager()

{

Cancel();

iTimer.Close();

}

void CActivityManager::ConstructL()

{

iTimer.CreateLocal();

}

EXPORT_C void CActivityManager::SetTimeout(TInt aTimeout)

{

iTimeout = aTimeout;

Reset();

}

EXPORT_C void CActivityManager::Reset()

{

Cancel();

Start();

}

void CActivityManager::DoCancel()

{

iTimer.Cancel();

iWatch = ENone;

}

The iWatch variable implements the state machine of the active object: we are either doing nothing, or monitoring inactivity or monitoring activity. The core methods are Start() and RunL(). This is the implementation of Start():

EXPORT_C void CActivityManager::Start()

{

if (!IsActive())

{

iWatch = EWaitingForInactivity;

iTimer.Inactivity(iStatus, iTimeout);

SetActive();

}

}

Essentially we set the state variable to monitoring inactivity and launch the inactivity notification offered by Rtimer by specifying the desired timeout in seconds. RunL() willl be executed after iSeconds seconds of user inactivity. Note that any previous user inactivity period is taken into consideration. This means that if there have already been, for example, 5 seconds of user inactivity when we issue the call, and we request to be notified after 10 seconds of user inactivity, then the call will complete in 5 seconds and not in 10 seconds.

Another thing which is very important and is at the core of the mechanism to detect user activity after an inactivity period is that we are not notified for an interval less than the current inactivity time. To explain it better, if we request to be notified after 3 seconds of user inactivity but the system has already been inactive for 5 seconds then we are not notified until activity is resumed and a following 3 second inactivity period occurs.

This is the implementation of RunL():

void CActivityManager::RunL()

{

if (iStatus == KErrNone)

{

if (iWatch == EWaitingForInactivity)

{

TInt inactivity = User::InactivityTime().Int();

if (inactivity >= iTimeout)

{

if (iObserver)

{

iObserver->InactivityDetected();

}

if (!IsActive()) //observer might have called a Reset()

{

iTimer.Inactivity(iStatus,0);

iWatch = EWaitingForActivity;

}

}

else

{

iTimer.Inactivity(iStatus,iTimeout);

}

}

else if (iWatch == EWaitingForActivity)

{

if (iObserver)

{

iObserver->ActivityDetected();

}

if (!IsActive()) //observer might have called a Reset()

{

iTimer.Inactivity(iStatus,iTimeout);

iWatch = EWaitingForInactivity;

}

}

if (!IsActive()) //observer might have called a Reset()

{

SetActive();

}

}

else

{

iWatch = ENone;

}

}

As you can see it is a simple binary state machine going from monitoring inactivity to monitoring activity and so forth and calling the appropriate observer callbacks. After an inactivity period we use a call to Rtimer::Inactivity(iStatus, 0) to be notified of activity again. This is the trick to detect activity without polling User::InactivityTime(). If there has already been any inactivity period longer than 1 second, Rtimer::Inactivity(iStatus,0) will in fact complete exactly when activity is resumed.



In Series 60 you can find a library called ActivityManager.dll. This library provides the same functionality as this active object. However because the API for this library is private (you will not find the header in the SDK as far as I know) and because it is only one class it might be worth to implement this class again rather than reverse engineer ActivityManager.dll.

Please note this code was tested on the Series 60 emulator, the Nokia 7650 and 3650. It should work on any symbian version but depending on what you need to do there might be a simpler way. For example, if you want to write a screen saver, in Series 60 2.0 the default screen saver supports extension plug-ins and you do not need to worry about this.

相关文章:
How to detect if an application is launched by user or the startup list
Using SIP with Nokia Series60 and Asterisk
Getting the Current Cell Id using Symbian S60
My experiences making a Task Manager
Symbian OS Exec Calls
An application for Series 60 - a step-by-step example
Detecting user inactivity
Programming IrComm3 wire raw
 

站点地图 | 加入收藏 | 联系站长 | 广告服务 |
QQ:280529124  Tel:0592-8271361 辽ICP备05021703号