Handling Inbound Connections
As mentioned previously, when an application is running, the AMS assumes the application will handle all inbound connections. However, if the AMS starts a MIDlet in response to an inbound connection there are a few things you will need to know in order to handle the inbound connection.
Getting a List of Connections
When the AMS receives an inbound connection notification, the MIDlet corresponding to the registered connection is instantiated and the startApp() method is invoked. Once startApp() is invoked, the MIDlet is responsible for taking over the inbound connection. A list of connections can be obtained by calling PushRegistry.listConnections(boolean). The boolean parameter indicates if the caller is interested in all connections associated with this MIDlet suite or just the connections with input available (i.e., the input from the inbound connection that caused the AMS to start the MIDlet). This method returns an array of strings from the PushRegistry. These strings can be passed directly to Connector.open() to open the connection.
If the inbound connection is a datagram, the AMS must guarantee that the original datagram that triggered the push notification is available once the MIDlet starts. However, if additional datagrams are received by the device before the MIDlet can take over the connection, these subsequent datagrams might be lost. This behavior is platform dependent. It's important to know that you may experience different behavior for pushed datagrams on two different devices.
If the inbound connection is a socket, the AMS is responsible to get the socket connection transferred to the MIDlet. However, there is a chance that the server could timeout the socket connection before handoff occurs. For this reason it is important to write your startApp() method so that the MIDlet starts quickly and takes control of the connection as soon as possible.
As a best practice, you should consider handling network connections on a thread separate from the user interface thread. Network calls can block the user interface from redrawing or responding to user input until the call returns. In some cases having the user interface and a network connection on the same thread can cause a device to deadlock. For example, if an untrusted MIDlet attempts the make an HTTP connection, the device may need to prompt the user for permission to use this service. The connection blocks until this user permission is granted. However, if the device needs to use the same thread to prompt the user for this permission, the prompt cannot be displayed. This is because the network is blocking, waiting for the response from the user prompt. Thus, a deadlock can ensue leaving the application in a hung state.
Listing 1 provides an example of how to handle inbound datagram connections in response to a pushed datagram connection.
The code in startApp() (Listing 1) creates a DatagramHandler object to process incoming datagrams on a separate thread from the main application. There is also an init flag in place to make sure that pausing and resuming the MIDlet does not cause the code to run multiple times when you don't want it to.
Now that you have some familiarity with how to register and handle pushed connections, I'll now look at another feature of the PushRegistry that allows MIDlets to be started without direct user interaction called an Alarm.
Hidden away in the API of the PushRegistry is a simple little feature called an Alarm. An Alarm can be registered for a MIDlet suite much like a connection. The difference, however, is that the MIDlet associated with an Alarm is started at a certain point in time, rather than in response to network activity. Each MIDlet suite can register, at most, one Alarm at a time. Alarms are registered by making a call to PushRegistry.registerAlarm(). The following code registers an Alarm to start the MIDlet "PushDemo" 24 hours from now.
long day = 1000*60*60*24;
long t = new Date().getTime()+day;
Some devices may not support the ability to launch an application using an Alarm. In these cases, a ConnectionNotFoundException
will be thrown if the application attempts to register an alarm. Furthermore, depending on the security restrictions of the device, the user may be prompted to accept or reject the Alarm. Rejecting would abort the launch of your MIDlet. The MIDlet is not allowed to run until the user responds to the prompt.
If the MIDlet does not have permission to execute in response to an Alarm, a SecurityException may be thrown. As with connections, if the MIDlet suite is running, the AMS will ignore settings in the PushRegistry. A running suite must use a Timer and TimerTask to periodically run tasks. The PushRegistry and AMS only get involved when the MIDlet suite is not running.
Pushed to the End
In this article I've discussed two ways a MIDlet can be started by the AMS using the PushRegistry: by registering a push connection or an Alarm. It's important to remember, however, that once a MIDlet suite is running, the AMS will ignore inbound connection notifications as well as any registered alarms. It is the suite's responsibility to handle these activities while running, even if the MIDlet suite is in the paused state.