Yesterday, I found myself using an old piece of code that I wrote ages ago. It's something I've used every now and then for past few years. Since I myself find it useful, I might as well share it. All the code does is display a Notification Bubble in Windows Mobile. To do this you use the Notification class in the Microsoft.WindowsCE.Forms namespace. Even though the Notification class is very straight forward and easy to use, I created a helper class so that I only need to write one line of code for displaying a notification bubble: NotificationBubble.Show(2, "Caption", "Text");
///<summary>
/// Used for displaying a notification bubble
///</summary>
publicstaticclassNotificationBubble
{
///<summary>
/// Displays a notification bubble
///</summary>
///<param name="duration">Duration in which the notification bubble is shown (in seconds)</param>
This is a task that pretty much every mobile device can do, or at least any mobile phone can do. In this short post on multi-platform mobile development I would like to demonstrate how to send an SMS or launch the SMS compose window in a mobile application.
I'm going to demonstrate how to use the messaging API's of the following platforms:
Android
Windows Phone 7
Windows Mobile 5.0 (and higher) using .NET Compact Framework
Windows Mobile using the Platform SDK (Native code)
Android
There are 2 ways of sending SMS from an Android application: Launching the Compose SMS window; Through the SmsManager API. I figured that since this article is supposed to demonstrate as many ways as possible for sending SMS that I create a helper class containing methods that I think would be useful or at least convenient to have.
Here's a SMS helper class for Android that I hope you would find useful.
/**
* Helper class for sending SMS messages
*
* @author Christian Resma Helle
*/ public class Sms { private final static String SENT_ACTION = "SENT"; private final static String DELIVERED_ACTION = "DELIVERED"; private Context context; private PendingIntent sentIntent; private PendingIntent deliveredIntent;
/**
* Creates an instance of the SMS class
*
* @param context Context that owns displayed notifications
*/ public Sms(Context context) { this.context = context;
registerForNotification(); }
private void registerForNotification() { sentIntent = PendingIntent.getBroadcast(context, 0, new Intent(SENT_ACTION), 0);
deliveredIntent = PendingIntent.getBroadcast(context, 0, new Intent(DELIVERED_ACTION), 0);
context.registerReceiver(messageSentReceiver, new IntentFilter(SENT_ACTION));
context.registerReceiver(messageDeliveredReceiver, new IntentFilter(DELIVERED_ACTION)); }
/**
* Opens the Compose SMS application with the recipient phone number displayed
*
* @param phoneNumber recipient phone number of the SMS
*/ public void composeMessage(String phoneNumber) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sms:" + phoneNumber));
context.startActivity(intent); }
/**
* Opens the Compose SMS application with the recipient phone number and message displayed
*
* @param phoneNumber recipient phone number of the SMS
* @param text message body
*/ public void composeMessage(String phoneNumber, String text) { Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("sms_body", text);
intent.putExtra("address", phoneNumber);
intent.setType("vnd.android-dir/mms-sms");
context.startActivity(intent); }
/**
* Opens the Compose SMS application with the multiple recipient phone numbers and the message displayed
*
* @param phoneNumber recipient phone numbers of the SMS
* @param text message body
*/ public void composeMessage(String[] phoneNumbers, String text) { StringBuilder sb = new StringBuilder(); for (String string : phoneNumbers) { sb.append(string);
sb.append(";"); } composeMessage(sb.toString(), text); }
/**
* Send an SMS to the specified number
*
* @param phoneNumber recipient phone number of the SMS
* @param text message body
*/ public void sendMessage(String phoneNumber, String text) { sendMessage(phoneNumber, text, false); }
/**
* Send an SMS to the specified number and display a notification on the message status
* if the notifyStatus parameter is set to <b>true</b> *
* @param phoneNumber recipient phone number of the SMS
* @param text message body
* @param notifyStatus set to <b>true</b> to display a notification on the screen
* if the message was sent and delivered properly, otherwise <b>false</b> */ public void sendMessage(String phoneNumber, String text, boolean notifyStatus) { SmsManager sms = SmsManager.getDefault(); if (notifyStatus) { sms.sendTextMessage(phoneNumber, null, text, sentIntent, deliveredIntent); } else { sms.sendTextMessage(phoneNumber, null, text, null, null); }
}
/**
* Send an SMS to multiple recipients and display
*
* @param phoneNumber recipient phone number of the SMS
* @param text message body
*/ public void sendMessage(String[] phoneNumbers, String text) { sendMessage(phoneNumbers, text, false); }
/**
* Send an SMS to multiple recipients and display a notification
* on the message status if notifyStatus is set to <b>true</b> *
* @param phoneNumber recipient phone number of the SMS
* @param text message body
* @param notifyStatus set to <b>true</b> to display a notification on the screen
* if the message was sent and delivered properly, otherwise <b>false</b> */ public void sendMessage(String[] phoneNumbers, String text, boolean notifyStatus) { StringBuilder sb = new StringBuilder(); for (String string : phoneNumbers) { sb.append(string);
sb.append(";"); } sendMessage(sb.toString(), text, notifyStatus); }
private BroadcastReceiver messageSentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK:
Toast.makeText(context, "SMS sent", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(context, "Generic failure", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(context, "No service", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(context, "Null PDU", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(context, "Radio off", Toast.LENGTH_SHORT).show(); break; }
}
};
private BroadcastReceiver messageDeliveredReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK:
Toast.makeText(context, "Message delivered", Toast.LENGTH_SHORT).show(); break; case Activity.RESULT_CANCELED:
Toast.makeText(context, "Message not delivered", Toast.LENGTH_SHORT).show(); break; }
}
}; }
Before your Android application can send SMS it needs the right permissions for it. Add the SEND_SMS permission your AndroidManifest.xml
Here are some examples on how to use the SMS helper class defined above from within an Activity class:
Sms sms = new Sms(getApplicationContext());
// Send an SMS to the specified number sms.sendMessage("+4512345678", "Multi-platform Mobile Development");
// Send an SMS to the specified number and display a notification on the message status sms.sendMessage("+4512345678", "Multi-platform Mobile Development", true);
// Send an SMS to multiple recipients sms.sendMessage(new String[] { "+4512345678", "+4598765432" }, "Multi-platform Mobile Development");
// Send an SMS to multiple recipients and display a notification on the message status sms.sendMessage(new String[] { "+4512345678", "+4598765432" }, "Multi-platform Mobile Development", true);
// Opens the Compose SMS application with the recipient phone number displayed sms.composeMessage("+4512345678");
// Opens the Compose SMS application with the recipient phone number and message displayed sms.composeMessage("+4512345678", "Multi-platform Mobile Development");
// Opens the Compose SMS application with the multiple recipient phone numbers and the message displayed sms.composeMessage(new String[] { "+4512345678", "+4598765432" }, "Multi-platform Mobile Development");
Windows Phone 7
This platform unfortunately doesn't provide as vast a API collection compared to Android and Windows Mobile. To send an SMS in Windows Phone 7, you will have to use the SMS Compose page in the built-in messaging application. To launch this we call the Show() method in SmsComposeTask.
Here's how to use SmsComposeTask
SmsComposeTask launcher = newSmsComposeTask();
launcher.To = "+45 12 34 56 78";
launcher.Body = "Multi-platform Mobile Development";
launcher.Show();
Windows Mobile 5.0 (and higher) using .NET Compact Framework
Sending an SMS in this platform is just as easy as doing so in Windows Phone 7. Windows Mobile provides native API's for the Short Messaging System, these methods are exposed as C type methods in a DLL called sms.dll. Aside from the SMS API, the platform also offers another API called the Messaging API (CE MAPI) for sending SMS, MMS, and Emails. Microsoft has provided managed wrappers for these and many other API's to make the life of the managed code developer a lot easier.
To send an SMS in Windows Mobile 5.0 (and higher) we use the SmsMessage object. There are 2 ways of accomplishing this: Using the Send() method of the SmsMessage class; Sending the SMS using the Compose SMS application
Here's a snippet on how to send SMS using the Send() method
The code above depends on 2 assemblies that must be referenced to the project:
Microsoft.WindowsMobile.dll
Microsoft.WindowsMobile.PocketOutlook.dll
It is also possible to P/Invoke the SMS API through sms.dll, but this requires a slightly more complicated solution. In the next section, I will demonstrate how use the SMS API in native code. This should give you an idea on how to use the SMS API if you would like to go try the P/Invoke approach.
Windows Mobile using the Platform SDK (Native code)
Probably not very relevant for most modern day managed code developers but just to demonstrate as many ways to send SMS in as many platforms as possible I'd like to show how to send SMS in native code using the Windows CE Short Message Service (SMS) API.
Here's a sample C++ helper class for sending SMS using the Platform SDK
The code above requires the that the project is linked with sms.lib, otherwise you won't be able to build.
Here's a snippet of how to use the SMS helper class defined above:
SmsMessage *sms = new SmsMessage(L"+14250010001", L"Multi-platform Mobile Development");
sms->Send();
delete sms;
For those who don't know what +14250010001 is, this is the phone number of the Windows Mobile emulator. For testing SMS functionality on the emulator, you can use this phone number.
That's it for now. I hope you found this article interesting.
Not so long ago I had a project that involved Bluetooth communication from a windows mobile device to some custom designed hardware. Everything went smoothly with only a few bumps during the scope of the project. When we had the applications on the field, certain users where running on devices that used the Widcomm Bluetooth Stack and that gave us a few headaches. For one, our system doesn't use any security features in bluetooth hence it doesn't not require pairing. Our security architecture is service based and checks for certain keys being passed back and forth to an online service. Very standard stuff. The problem we had with the devices running on a Widcomm Bluetooth stack was that the user was always prompted to pair even though the device did not require pairing. The application was not designed to handle user input aside from logging in/out and some diagnostic features. The application was designed to just run quietly in the background with the device tucked in the users pocket.
Since quite a few devices use the Widcomm Bluetooth Stack I needed a quick fix/hack to avoid the user having to pick up the device and click "Yes" on the security prompt to communicate with the device. The fix had to be as simple as possible and had to run without disrupting the user. My not so clean solution was to create a small application that does nothing but check if the Widcomm security pairing prompt app was running and if so send a keystroke event to simulate the user clicking on "Yes".
The Widcomm security prompt app main window uses the class name Broadcom_BTWizard with the window name Bluetooth. I check if this window exists and send the F1 keyboard event to simulate clicking on the left hardware button on the device
This is of course not the best solution but if you have a similar problem then this might save you some time if your only requirement is to get it to work as soon as possible. Otherwise, I would suggest avoiding the Widcomm Bluetooth Stack and just go for devices that use the Microsoft Bluetooth Stack
In this short post I'd like to demonstrate how to retrieve a list of installed applications on a Windows Mobile device using OMA Client Provisioning. First you need to add a reference to the Microsoft.WindowsMobile.Configuration assembly. To retrieve the list we need to process a specific configuration (UnInstall Configuration Service Provider) using the ConfigurationManager.ProcessConfiguration method. The configuration is described in an XML and the response to this will also be described in XML
To query the device we process this configuration:
<wap-provisioningdoc>
<characteristic-querytype="UnInstall"/>
</wap-provisioningdoc>
The query above will only return installed application that can be uninstalled. The device would then respond with something like this:
<wap-provisioningdoc>
<characteristictype="UnInstall">
<characteristictype="Microsoft Application#2">
<parmname="uninstall"value="0"/>
</characteristic>
<characteristictype="Microsoft Application#1">
<parmname="uninstall"value="0"/>
</characteristic>
<characteristictype="Demo Home Screen">
<parmname="uninstall"value="0"/>
</characteristic>
</characteristic>
</wap-provisioningdoc>
And here's how to accomplish this task using .NETCF and C#
I recently had a project where I needed to send data to Bluetooth devices. The client applications where to run in several platforms, currently only J2ME (Nokia phones) and Windows Mobile phones. Windows Mobile actually offers a pretty decent Bluetooth stack but not all devices use this. One of the devices I needed to use used the Widcomm stack. Luckily, there is an open source project called 32feet.NET which came in very handy for providing a layer over the 2 different stacks I use. The 32feet.NET library was also incredibly easy and fun to use.
In this article I'd like to demonstrate how to enumerate Bluetooth devices using .NETCF and the 32feet.NET library. The following code will work on both Microsoft and Widcomm Bluetooth stacks:
using System.Diagnostics;
using InTheHand.Net.Sockets;
namespace BluetoothSample
{
staticclassProgram
{
privatestaticvoid Main()
{
BluetoothDeviceInfo[] devices;
using (BluetoothClient sdp = newBluetoothClient())
devices = sdp.DiscoverDevices();
foreach (BluetoothDeviceInfo deviceInfo in devices)
An interesting thing I had to consider for this project was the CPU architecture or endianness of the device I'm running on and the device I'm sending data to. I needed to reverse the byte order of the numeric data I sent and received.
I've seen some people ask how to crop an image in .NET Compact Framework in the community. Although the operation is pretty simple, I'll share a code snippet anyway.
I recently discovered a new book called .NET Compact Framework 3.5 Data Driven Applications. I've so far only read a few chapters but it seems like a promising book providing a lot of examples.
In order to use the function we need to create a few GDI objects: a Pen to draw the border, and a Brush to fill the rectangle. We will mostly use P/Invoke for creating and releasing GDI objects
constint PS_SOLID = 0;
constint PS_DASH = 1;
[DllImport("coredll.dll")]
staticexternIntPtr CreatePen(int fnPenStyle, int nWidth, uint crColor);
[DllImport("coredll.dll")]
staticexternint SetBrushOrgEx(IntPtr hdc, int nXOrg, int nYOrg, refPoint lppt);
Let's wrap all the code above as extension methods to the Graphics class and use them in our owner drawn button control. A button control is one of the easiest owner drawn controls to create. Let's keep it as simple as possible and only have 2 states for our button: pressed and not pressed.