Introduction
This program is a proof of concept for a larger system that I plan to build. Ultimately, I would like to have a system that allows users to opt in and out of letting their locations be known. The location information would be acquired through an application running on a Windows Mobile 5.0 (or later) device. Such a system has commercial applications (knowing where a delivery or service person is located) and personal applications (e.g.: you are heading to a friend's house and the friend would like to know how far away you are). In this prototype, my goal is to touch on some of the foundational technologies for the system.
For this proof of concept, I wanted to be able to acquire the GPS information from the GPS Intermediate Driver, and wanted a way to have a phone send this information either by request of the phone's owner or one of the owner's contacts. Thus, the fundamental technologies used here are:
- GPS Intermediate Driver - gets GPS information in a way that won't interfere with other GPS applications.
- MessageInterceptor - waits for location request and starts the application when one is received.
Required Tools
To run this code, you will need to have Visual Studio 2005 installed, and both the Windows Mobile 5.0 SDK and the Windows Mobile 6 Professional SDK. The 5.0 SDK is needed because I've set this project to target 5.0 devices. The code used for accessing the GPS device is part of the 6.0 SDK (though it runs just fine on 5.0 devices). I've included the compiled assembly for the GPS wrapper with my project, but not the source code. To see the source code for this wrapper, you must have the Windows Mobile Professional 6.0 SDK.
I would also suggest that you have a Windows Mobile 5.0 device to test the application with. You can use the emulators for testing the program. This program makes use of SMS messaging. Depending on your service plan with your phone company, you may have to pay fees for every message sent and received. I fall into this category, as at this point in time, available carriers here in the United States do not allow many phones to have unlimited text message subscriptions on the same phone line as a one that has an unlimited data subscription. Because of this, the emulators may be preferable for initial testing of the program. You can redirect the COM port of the emulated Windows Mobile device to an external GPS receiver connected to your PC, or you can use the "FakeGPS" program available in the Windows Mobile 6.0 SDK to also emulate a GPS receiver.
The Missing GPS Settings Icon
On phones with Windows Mobile 5 Professional and later (the phones with touch sensitive screens), there is an icon in the Settings menu that allows one to set the hardware port over which their GPS receiver communicates. On some rather popular Windows Mobile phones, this icon is missing. It is not erased. Rather, some OEMs saw fit to hide the icon. The icon can be restored by deleting the Registry keys [HKEY_LOCAL_MAHINE\ControlPanel\Settings\GPS Settings\Hide] and [HKEY_LOCAL_MAHINE\ControlPanel\Settings\GPS Settings\Redirect]. If you don't have a registry editor, you can delete these keys by running the GPS Icon Restoration Program attached to this article. Simply copy it to your phone and run it. It will display a message box letting you know that it was successful or that those keys do not exist. You may need to reset your phone after running this program, for the changes to take affect.
How Does this Program Work
When initially run, the owner of the phone is able to enter a pin that will be used to identify location request messages. When an SMS message is received, if it contains the PIN that the user selected, this program will be started up (if it is not already running) and the message will be passed to the program. All other messages will be handled as usual on the phone. When the message is received, the program reads the current GPS coordinates from the phone, and responds back to the sender with a link to a map on local.live.com showing the phone owner's current location.
Catching SMS Messages with the MessageInterceptor Class
As its name suggests, the MessageInterceptor
class is used to capture incoming SMS messages and allow your code to act upon receiving the message. Rather than needing to manually check all of the messages yourself, you set up a message rule for the types of messages that you are interested in. Within this program, there is only one property on the class that we have interest in: MessageCondition
.
The MessageCondition
member is of a class by the same name, MessageCondition
. The MessageCondition
allows you to specify a string that will be searched for in the message. You can specify that the string must be at the beginning, end, or anywhere within the message, and you can specify whether or not the search is case sensitive. For this program, I've set the MessageCondition
class to only search within the body of the message for the presence of your pin anywhere in the message.
_messageInterceptor.MessageCondition = new MessageCondition();
_messageInterceptor.MessageCondition.CaseSensitive = false;
_messageInterceptor.MessageCondition.ComparisonType =
MessagePropertyComparisonType.Contains;
_messageInterceptor.MessageCondition.ComparisonValue = this.txtPin.Text;
_messageInterceptor.MessageCondition.Property = MessageProperty.Body;
Once the condition is set, the MessageInterceptor
only needs to be enabled, and an event handler must be given to it:
_messageInterceptor.EnableApplicationLauncher(ruleName);
_messageInterceptor.MessageReceived += _messageInterceptorEventHandler;
The user may have exited the program since the MessageInterceptor
was created. If a message is received after exiting the program and if the user left the program in an enabled state, then the program will be automatically started. To catch messages that caused the program to start, we must create the MessageInterceptor
class in the program's Load
event. During load, the program checks to see if the application had registered to be automatically loaded up receiving a message. If that is the case, then the program creates a new MessageInterceptor
and gives it an event handler. The application will then receive notification of that message through the event handler.
if (MessageInterceptor.IsApplicationLauncherEnabled(ruleName))
{
_messageInterceptor = new MessageInterceptor(ruleName);
_messageInterceptor.MessageReceived +=
new MessageInterceptorEventHandler(_messageInterceptor_MessageReceived);
txtPin.Text = _messageInterceptor.MessageCondition.ComparisonValue;
this.chkFindMeEnabled.Checked = true;
}
else
{
this.chkFindMeEnabled.Checked = false;
}
Obtaining the Current Location
The Intermediate GPS Driver handles the details of interfacing to the GPS hardware for us. I'm using a wrapper included in the Windows Mobile 6 SDK that simplifies the use of the driver. The code works well, and is easy to use, so I would encourage you to consider using it instead of creating your own GPS reading code. Initializing the GPS object can be done in a few lines of code:
gps = new Gps();
gps.LocationChanged +=
new LocationChangedEventHandler(gps_LocationChanged);
gps.Open();
The EventArgs
received from the LocationChanged
event contains more details than you'll probably ever need from the GPS receiver. I simply save the Position
member from the EventArgs
and update the _currentLocation
object.
void gps_LocationChanged(object sender, LocationChangedEventArgs args)
{
if (args.Position.LatitudeValid && args.Position.LongitudeValid)
{
currentPosition = args.Position;
UpdatePosition();
}
}
When the program no longer needs to use the GPS Receiver, a call to Gps.Close()
is made to end the object's worker thread. Not doing this could cause the program to never terminate.
Sending a Message
Sending messages is straightforward. In the case of SMS messages, a new SMSMessage
object is created with the receiver's number and the message text as its constructor arguments. Then, the object's Send()
method is called to deliver the message. Since an SMS message cannot be more than 160 characters, the link sent in the SMS message only contains a user's coordinates and a pushpin.
It would not be practical to receive the SMS message containing the map link on a phone, so you may wonder why the program has this ability. You must remember that computers can also send SMS messages either through another application such as Live Messenger or through built-in hardware such as a GMS modem or CDMA modem.
public void SmsSendCoordinates(string to,GpsPosition pos)
{
string message = String.Format(responseTemplate,
pos.Latitude, pos.Longitude);
SmsMessage sms = new SmsMessage(to, message);
sms.Send();
this.eventLog.Add(DateTime.Now, to, pos);
}
Sending e-mail messages is just as simple. Create a new email object, populate a subject and body, add an address to the "To" collection, and then call its Send()
method. The Send()
method for e-mail requires an argument that was not needed for SMS. That argument is the name of the mail account to use. On my phone, the available accounts are named "ActiveSync" and "MMS". Naturally, I would rather not use MMS since my phone service provider charges what I feel to be high tariffs for sending a message via MMS.
Since the 160 character limit is not applied against e-mails I am at liberty to place more information in the link. So when sending an e-mail the program may (Depending on the user's selected options) include custom text and an image for representing the user.
public void EmailSendCoordinates(string emailAddress, GpsPosition pos)
{
string avatarUrl = string.Empty;
string displayName = string.Empty;
string customMessage=string.Empty;
if(((_Settings.OptionFlags&OptionChangedFlags.Avatar)==
OptionChangedFlags.Avatar)&& (_Settings.Avatar.Length>0)
)
avatarUrl=_Settings.Avatar;
displayName = optionsUI.DisplayName;
customMessage = optionsUI.CustomMessage;
string message = String.Format(detailedResponseTemplate,
pos.Latitude, pos.Longitude,
Utility.UrlEncode(avatarUrl), Utility.UrlEncode
(displayName), Utility.UrlEncode(customMessage));
EmailAccount account =
(new OutlookSession()).EmailAccounts[_Settings.EmailAccount];
EmailMessage msg = new EmailMessage();
msg.To.Add(new Recipient(emailAddress));
msg.Subject = "My location";
msg.BodyText = message;
msg.Send(account);
this.eventLog.Add(DateTime.Now, emailAddress, pos);
}
What's Next
There are quite a number of features I would like to add to this program. In the next revision, I plan to add a mapping control so that users can see each other's location from their phones. I may also add support for Windows Mobile 5 Standard Edition (the devices with no touch screens). To accomplish this, there needs to exist a web server. Once those two pieces are working, I plan to use the Windows Live Search and MapPoint APIs to provide functionality for finding points of interest and getting directions to them so that users can meet each other.
History
- 15 August 2007 - Article published.