Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Mobile Development: Manage the event db, What Wakes Up Your Device

5.00/5 (1 vote)
13 May 2013CPOL1 min read 8.4K  
The event db (it is my naming) holds all events and actions that can be invoked to launch an app or fire some events.

The event db (it is my naming) holds all events and actions that can be invoked to launch an app or fire some events.

NotificationList

The tool shows all known notifications on a WM device. You can browse the event db and examine the defined events. Additionally, the tool shows power change notifications.

noti_01 noti_02 noti_03

In the mid window above, you can see there is a timed event that will occur at 0:00 and start \windows\calupd.exe. This will wake your device all night and update the calendar entries for re-occurring schedules, etc.

The right window shows the power notifications on a suspend/resume cycle.

Using the options menu, you can save a list of the defined notification events.

There are different notification types:

C#
public enum CeNotificationType
{
    CNT_EVENT = 1,          //@flag CNT_EVENT  | System event notification
    CNT_TIME,               //@flag CNT_TIME   | Time-based notification
    CNT_PERIOD,             //@flag CNT_PERIOD | Time-based notification is active for
                            // time period between stStart and stEnd
    CNT_CLASSICTIME         //@flag CNT_CLASSICTIME | equivalent to using (obsolete)
    // CeSetUserNotification function - standard command line is
    // supplied. lpszArguments must be NULL
}

CeSetUserNotification is spared here. This structure is used to display user notification bubbles on the screen.

The notification API enables you to setup notification for different events:

C#
public enum CeNotificationEvent
{
    NOTIFICATION_EVENT_NONE,
    NOTIFICATION_EVENT_TIME_CHANGE,
    NOTIFICATION_EVENT_SYNC_END,
    NOTIFICATION_EVENT_ON_AC_POWER,
    NOTIFICATION_EVENT_OFF_AC_POWER,
    NOTIFICATION_EVENT_NET_CONNECT,
    NOTIFICATION_EVENT_NET_DISCONNECT,
    NOTIFICATION_EVENT_DEVICE_CHANGE,
    NOTIFICATION_EVENT_IR_DISCOVERED,
    NOTIFICATION_EVENT_RS232_DETECTED,
    NOTIFICATION_EVENT_RESTORE_END,
    NOTIFICATION_EVENT_WAKEUP,
    NOTIFICATION_EVENT_TZ_CHANGE,
    NOTIFICATION_EVENT_MACHINE_NAME_CHANGE,
    NOTIFICATION_EVENT_RNDIS_FN_DETECTED,
    NOTIFICATION_EVENT_INTERNET_PROXY_CHANGE, 
    NOTIFICATION_EVENT_LAST = NOTIFICATION_EVENT_INTERNET_PROXY_CHANGE
};

Please note that not all devices support all these types. As the names are more or less speaking names, I do not explain these event types any further.

If you want to add your own periodic, timed, application, you should look at my Tasker application.

PowerNotifications

Although not directly related to the above events db, it may also be good to know how you can subscribe to power notifications. The sample uses the MS PowerNotifications Message queue. When registering for the power messages, you can define a filter to get only power notification messages you are interested in.

C#
const uint POWER_NOTIFY_ALL = 0xFFFFFFFF;
const uint PBT_TRANSITION          =  0x00000001;  // broadcast specifying system power state transition
const uint PBT_RESUME = 0x00000002;  // broadcast notifying a resume, specifies previous state
const uint PBT_POWERSTATUSCHANGE = 0x00000004;  // power supply switched to/from AC/DC
const uint PBT_POWERINFOCHANGE = 0x00000008;

Every message comes with a data structure:

C#
[StructLayout(LayoutKind.Sequential)]
struct POWER_BROADCAST
{
    UInt32 dwMsg;
    UInt32 dwFlags;
    UInt32 dwLength;
    string sSystemPowerState; //WCHAR SystemPowerState[1];
}

And we have a lot of flags to lookup:
C#
//
// System Power (Source/State/Option) Flags
//
[Flags]
enum PowerState:uint
{
    // upper bytes: common power state bits
    //#define POWER_STATE(f)           ((f) &  0xFFFF0000);        // power state mask
    POWER_STATE_NA              = 0x00,
    POWER_STATE_ON              = 0x00010000,        // on state
    POWER_STATE_OFF             = 0x00020000,        // no power, full off
    POWER_STATE_CRITICAL        = 0x00040000,        // critical off
    POWER_STATE_BOOT            = 0x00080000,        // boot state
    POWER_STATE_IDLE            = 0x00100000,        // idle state
    POWER_STATE_SUSPEND         = 0x00200000,        // suspend state
    POWER_STATE_UNATTENDED      = 0x00400000,        // Unattended state.
    POWER_STATE_RESET           = 0x00800000,        // reset state
    POWER_STATE_USERIDLE        = 0x01000000,        // user idle state
    POWER_STATE_BACKLIGHTON     = 0x02000000,        // device scree backlight on
    POWER_STATE_PASSWORD        = 0x10000000,        // This state is password protected.
}
[Flags]
enum PowerEventType
{
    PBT_TRANSITION = 0x00000001,
    PBT_RESUME = 0x00000002,
    PBT_POWERSTATUSCHANGE = 0x00000004,
    PBT_POWERINFOCHANGE = 0x00000008,
}

[Flags]
enum PowerState1
{
    POWER_STATE_ON = (0x00010000),
    POWER_STATE_OFF = (0x00020000),

    POWER_STATE_CRITICAL = (0x00040000),
    POWER_STATE_BOOT = (0x00080000),
    POWER_STATE_IDLE = (0x00100000),
    POWER_STATE_SUSPEND = (0x00200000),
    POWER_STATE_RESET = (0x00800000),
}

And, of course, we need some P/Invoke:

C#
#region DllImports
[DllImport("coredll.dll")]
private static extern IntPtr RequestPowerNotifications(IntPtr hMsgQ, uint Flags);
[DllImport("coredll.dll")]
private static extern uint WaitForSingleObject(IntPtr hHandle, int wait);
[DllImport("coredll.dll")]
private static extern IntPtr CreateMsgQueue(string name, ref MsgQOptions options);
[DllImport("coredll.dll")]
private static extern bool ReadMsgQueue(IntPtr hMsgQ, byte[] lpBuffer, 
        uint cbBufSize, ref uint lpNumRead, int dwTimeout, ref uint pdwFlags);
#endregion

The main work is done inside a thread function:

C#
private void DoWork()
{
    byte[] buf = new byte[10000];
    uint nRead = 0, flags = 0, res = 0;

    System.Diagnostics.Debug.WriteLine("starting loop");
    try
    {
        while (!done)
        {
            res = WaitForSingleObject(ptr, 2500);
            if (res == 0)
            {
                ReadMsgQueue(ptr, buf, (uint)buf.Length, ref nRead, -1, ref flags);
                //System.Diagnostics.Debug.WriteLine("message: " + 
                //  ConvertByteArray(buf, 0) + " flag: " + ConvertByteArray(buf, 4));
                uint flag = ConvertByteArray(buf, 4);
                string msg = "";
                msg += ((PowerState)flag).ToString();
                if (msg=="")
                    msg = "Unknown Flag: " + flag.ToString();
                if (msg=="0")
                    msg = "POWER_STATE_NA";

                if (msg != "")
                {
                    if(OnMsg!=null)
                        OnMsg(this, new PwrEventArgs(msg, flag));
                    System.Diagnostics.Debug.WriteLine(msg);
                }
            }
        }
    }
    catch (Exception ex)
    {
        if (!done)
        {
            System.Diagnostics.Debug.WriteLine("Got exception: " + ex);
        }
    }
    System.Diagnostics.Debug.WriteLine("loop ended");
}

The sample code implements some event and delegates that you can subscribe to get power notification messages.

The source code is available via https://win-mobile-code.googlecode.com/svn/trunk/NotificationList/NotificationsList

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)