Mobile Development: manage the event db, what wakes up your device
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.
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.
Example file:
App | Args | Event | Start | End | Type |
sqmevent.exe | ‘AppRunAtTime’ | None | 14052013 07:33 | 01010001 00:00 | Time |
\windows\enrollnot.exe | ‘AppRunAtTime’ | None | 14052013 12:00 | 01010001 00:00 | Time |
\Windows\calupd.exe | ‘AppRunAtTime’ | None | 15052013 00:00 | 01010001 00:00 | Time |
CALNOT.EXE | ‘AppRunAtTime’ | None | 20052013 00:00 | 01010001 00:00 | Time |
ceipui.exe | ‘AppRunAtTime’ | None | 27052013 23:48 | 01010001 00:00 | Time |
clocknot.exe | ‘AppRunAtTime’ | None | 03112013 02:00 | 01010001 00:00 | Time |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\MSPPDUGateway_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\WLMScheduler_TimeChangeEvent | ” | TimeZoneChange | 01010001 00:00 | 01010001 00:00 | Event |
\\.\Notifications\NamedEvents\WLMScheduler_TimeChangeEvent | ” | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
calnot.exe | ‘AppRunAfterRestore’ | RestoreEnd | 01010001 00:00 | 01010001 00:00 | Event |
calnot.exe | ‘AppRunAfterTimeChange’ | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
ceipui.exe | ‘AppRunAfterTzChange’ | TimeZoneChange | 01010001 00:00 | 01010001 00:00 | Event |
ceipui.exe | ‘AppRunAfterTimeChange’ | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
clocknot.exe | ‘AppRunAfterTimeChange’ | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
clocknot.exe | ‘AppRunAfterRestore’ | RestoreEnd | 01010001 00:00 | 01010001 00:00 | Event |
repllog.exe | ‘AppRunAfterRndisFnDetected’ | RndisFNDetected | 01010001 00:00 | 01010001 00:00 | Event |
repllog.exe | ‘AppRunAfterTimeChange’ | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
repllog.exe | ‘AppRunAtRs232Detect’ | RS232Detected | 01010001 00:00 | 01010001 00:00 | Event |
Tskschedule.exe | ‘-Time’ | TimeZoneChange | 01010001 00:00 | 01010001 00:00 | Event |
Tskschedule.exe | ‘-Time’ | TimeChange | 01010001 00:00 | 01010001 00:00 | Event |
You can see the applications or named events that are issued. Then there are arguments that are provided to the application. You can also see the event type.
There are different notification types:
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:
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 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 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.
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:
[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:
// // 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:
#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:
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 to get power notification messages.
Source code available via NotificationsList