Build a ‘SNAPI’ App that Utilizes Windows Mobile 5.0 Managed APIs

rior to Window Mobile 5.0 (WM5) even simple things such as checking battery status, sending an SMS, or programming Pocket Outlook were rather difficult. Fortunately, WM5 came with new managed APIs that expose a phenomenal number of abilities that will greatly enhance mobile applications.

Windows Mobile 5.0 offers many new APIs. Although they are spread across a number of different services, they are all focused on the common goal of improving developer productivity. In this article, I’ll focus on the State and Notification API (SNAPI). Using SNAPI, I’ll build a CallHandler application that automatically sends an SMS to a caller when the call recipient is busy and sets a Task reminder for the call recipient to return the call later.

The inspiration for this application is a new feature of some Nokia phones that ignores a call and sends a customized SMS to the caller (for example, to say that you’ll call back later). The WM5 managed APIs make this kind of application development really simple. In the bargain you will get a useful application for yourself and at the same time learn features of the State and Notification API.

Don’t Worry, Get SNAPI
Here’s the official description of SNAPI from Microsoft.

The State and Notification Broker API provides a unified mechanism for storing device, application, and system-state information. Beyond simply being a unified store, it provides centralized notification architecture, allowing applications to easily register for notification, optionally starting an application in the event that a value of interest should change. The model allows applications to easily share their own state information as well. Windows Mobile 5.0 devices ship with well over 100 different state values available through the State and Notification Broker.

So what does this mean for you? Let’s say you have a Windows Mobile application that is used for data collection. User-entered data must be backed up in this system when the battery level reaches, say, 15 percent. In order to do this you would need a way to check the current battery status?or better still to be notified when the battery level reaches 15 percent. Without WM5 this would be very difficult.

What You Need
Visual Studio.NET 2005
Windows Mobile 5.0 SDK for Pocket PC
And/Or
Windows Mobile 5.0 SDK for SmartPhone

You need an actual Windows Mobile 5 phone device to test the code sample.

Or suppose you needed to respond to an incoming SMS message on a WM5 device, how would you do it? Prior to WM5 this was not possible using Managed code; the only option was to use P/Invoke. SNAPI makes all of this easy using managed code.

Before you can use SNAPI in your code you need to add references to two assemblies to your code: Microsoft.WindowsMobile and Microsoft.WindowsMobile.Status. This will enable you to access SNAPI and a lot of other useful WM5 APIs. The SystemState class gives you the ability to get the current value of a system state as well as a notification when that state changes. SNAPI provides access to 100+ pieces of state information. You need to figure out which particular state you need to monitor. The object browser (Figure 1) is the perfect way to parse through the wealth of state information provided via SNAPI. It makes sense to browse this list to get an overview of the various system properties that are exposed via SNAPI.

Figure 1. Use the object browser inside Visual Studio to browse all the various system properties that SNAPI can monitor.

For example, if you wanted to know the current battery state you would capture the value by typing:

SystemState.GetValue(SystemProperty.PowerBatteryStrength)

This would get the remaining battery power level, expressed as a percentage of fully charged. Here I’m using the GetValue function of the SystemState class. It retrieves the value of a System Property using the property as a parameter.

Getting Notified of Changes
An incoming call is, basically, a change in state. Therefore you can employ the SystemState class to notify you when a call is coming in. To monitor a particular SystemState you need to define in your code an instance of the SystemState class and write event handling code for changes. To define an instance in your code you need to add the following line of code just after the default constructor of your form.

Friend WithEvents IncomingCall As New _SystemState(SystemProperty.PhoneIncomingCall)

Here I’m declaring IncomingCall as a new instance of the SystemState class and specifying the property of interest to me, which in this case is PhoneIncomingCall. To handle changes to this SystemProperty (PhoneIncomingCall) you need to write an event handler.

Private Sub CheckCallStatus(ByVal Sender As Object, ByVal Args As ChangeEventArgs) _Handles IncomingCall.Changed        MessageBox.Show("Call coming thru :-) ")End Sub

Try it Out!
Open Visual Studio, choose a project type of Smart Device ?>Windows Mobile 5.0 Pocket PC or SmartPhone and choose Device Application as the project template. On the default form that is created, press F7 to start writing code. Add references to the two assemblies, Microsoft.WindowsMobile and the Microsoft.WindowsMobile.Status, to your project and then add the imports statement to the start of your code file.

Imports Microsoft.WindowsMobileImports Microsoft.WindowsMobile.Status

Next, enter the code for the IncomingCall declaration followed by the CheckCallStaus method defined above. Once you’ve completed that, run the application by hitting F5 and choose an actual WM5 device as the target. Your application should load up. Now is the time to make a call to your device to test the application. As soon as an incoming call is detected the code for the call CheckCallStatus will execute, displaying the message “Call coming thru :-)”.

Author’s Note: Besides your application responding to the call, the default WM5 phone handler will also run, asking you to accept or ignore the call. Choose the ignore option.

You’ve just written your first application to handle a change in a SystemState(PhoneIncomingCall). But even though our message text displays properly, it’s not being delivered anywhere useful. The next step is capturing the phone number of the incoming caller. Declare a variable to store a phone number at your form class level; you can add this statement immediately after the IncomingCall declaration:

    Dim PhoneNumber As String

Next, use SystemState in the event handler you just wrote (CheckCallStatus) to retrieve the incoming caller phone number.

PhoneNumber = SystemState.GetValue(SystemProperty.PhoneIncomingCallerNumber)

Add the above line of code as the first line of the method (CheckCallStatus) and edit the text displayed in the MessageBox as shown below:

MessageBox.Show("Incoming Call No: " & PhoneNumber) 

You are now able to detect and respond to an incoming call and store the caller phone number. At this stage it’s best to handle situations where errors could creep up. Replace the code in the CheckCallStatus with the following:

If Not _        String.IsNullOrEmpty(SystemState.GetValue(SystemProperty.PhoneIncomingCallerNumber)) Then            PhoneNumber = SystemState.GetValue(SystemProperty.PhoneIncomingCallerNumber)            Me.BringToFront()            ' MessageBox.Show("Incoming Call No: " & PhoneNumber)End If

This new code does two things. First it ensures that only valid phone numbers are stored by checking to see if the value of the incoming phone number is Null or empty. Second, it ensures that the form is brought to the front, in case the user has minimized the application. For now you can see that I’ve commented out the display of the message box, as you are about to learn how to send that same message via SMS instead.

Sending an SMS
In order to send an SMS message you need to use the SmsMessage class. This class is present in the assembly Microsoft.WindowsMobile.PocketOutlook.

Add a reference to this assembly and in your form import the namespace:

Imports Microsoft.WindowsMobile.PocketOutlook

Create a Sub called SendSMSMessage which accepts as string parameter ‘msg’:

    Private Sub SendSMSMessage(ByVal msg As String)           Dim _smsMessage As New SmsMessage            _smsMessage.Body = msg            _smsMessage.To.Add(New Recipient(PhoneNumber))            _smsMessage.Send()    End Sub

To send an SMS message you need to specify two things: the message text or body and the message recipient(s). In the SendSMSMessage sub, I’ve created an instance of the SmsMessage class called “_smsMessage.” Next I’ve specified a value ‘msg’ as the message body and specified that this message should be sent to a particular phone number by passing the variable ‘PhoneNumber’ to the property “To” of this class by invoking it’s Add method. The application supports multiple recipients and, thus, this ‘To’ property gets the collection of intended message recipients. Next I’ve created a New Recipient Object by passing it the PhoneNumber as a string parameter. Finally, send the SMS message by invoking the Send method of the SmsMessage class. That’s all there is to sending an SMS message from your program.

Adding a Task Reminder
The last bit of functionality that I defined for this application is to create a reminder for the user that will prompt them to return the call later. To do this I want to create a new Outlook task for the user.

Define a new routine called SetTaskReminder.

    Private Sub SetTaskReminder()        'Create a an outlook session        Dim MySession As New OutlookSession        Dim start, due, reminder As Date        start = Now.AddMinutes(15)        due = Now.AddMinutes(20)        reminder = Now.AddMinutes(10)        'Define the Task and set it's properties        Dim ReminderTask As New Task        ReminderTask.Subject = "Call Tel:" & PhoneNumber        ReminderTask.DueDate = due        ReminderTask.StartDate = start        ReminderTask.ReminderSet = True        'ReminderTask.ReminderTime = reminder        'Bug in task.ReminderTime prevents one from setting time correctly, hence using 'the following as a workaround.        ReminderTask.ReminderTime = New Date(reminder.Year, reminder.Month, _        reminder.Day, reminder.Hour, reminder.Minute, reminder.Second)        ReminderTask.Body = "Call Tel:" & PhoneNumber                'Add the task to the current outlook session        MySession.Tasks.Items.Add(ReminderTask)        ReminderTask.Update()    End Sub

To add a task to Outlook tasks, you have to create an instance of the OutlookSession class and add the task. The next thing that happens in the above code is the creation of three variables to store the start time, due time, and the reminder time for the task.

Next I’ve created an instance of Task Class and specified its properties such as the Subject of the task, the DueDate, The StartDate, and specifying that a reminder is required. It’s important to note that, as of this writing, there is a bug in the ReminderTime property, which Microsoft has not yet resolved. The property is supposed to accept a date, but in my code I’ve provided each value separately?including the year, month, day, reminder hour, reminder minute, and second values.

Next I’ve provided a value for the body of the task and added this task to the OutlookSession and fired an update. This adds a reminder task. If you also provide the subject or the body of the message the phone number data in the exact format as given above WM5 will recognize the number as a phone number and allow the device user to call that phone number without dialing.

Wrapping it Up
So far you have written code with three abilities:

  1. Gets notification of an incoming call and capture information about the call (phone number)
  2. Sends an SMS
  3. Creates a task/reminder.

You now need to orchestrate all the above and allow the user to create the message and execute this functionality when he or she chooses.

Add the following controls to the main form of your application.

  1. TextBox
  2. Button

Set the TextBox’s text property to “Will call later”.
Set the Button’s text property to Submit.

Double-click the button to add code to its click event and call the two methods defined earlier (SendSMSMessage and SetTaskReminder) one after the other.

SendSMSMessage(TextBox1.Text)SetTaskReminder

That’s it! Run the application by hitting F5 and selecting your WM5 device as the target. The application loads with the default form. To test it, call your phone from another mobile phone. This will invoke the CheckCallStatus method. The variable PhoneNumber will be assigned the value of the incoming caller phone number. If you click the submit button, the message “Will call later” (or whatever you happened to put in the text box) will be sent to the caller. In addition a task/reminder will be created on the receiving phone.

Enhancements to Consider
Some things you might want to do to enhance the code further:

  • Provide the user the ability to have a list of common messages such as “In a meeting,” “On another call” etc.
  • Add error-handling code to check that the phone number is actually a number. (For example, you want to handle blocked phones such as “Private Caller” or something similar. In addition, you need to trap for land line (POTS) numbers as these will not be able to receive a text message and different countries display numbers in different ways.)
  • Enhancing the SMS functionality by giving the user an option for delivery notification.

By now you’ve gotten a good introduction to SNAPI and you’ve seen how it can help you build a more responsive application. There are numerous others such as the Microsoft.WindowsMobile.PocketOutlook.MessageInterception Namespace, which provides classes for SMS message interception or classes to work with the Media Player etc. It is a rich environment that enables one to build a number of interesting applications that were either too difficult or impossible before.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts