The Developer Support team often sees cases in which Content Providers report that their app
does not load on a particular device. In most of these cases, the source of the problem is
usually coding errors in how the device handles the JAD and Manifest files during app download
and installation.
To help avoid errors in your MIDP application, keep the following rules in mind:
JAD and Manifest file attributes must be properly matched. Attributes that are
mismatched will cause errors in the installation process. Manifest and Java Application
Descriptor (JAD) files must contain the following attributes:
JAD and Manifest files must not contain attributes with empty values.
MIDlet-Permissions must be in order. Don't call an API that is not declared, and don't call an API that you are not certified to have. Use the MIDlet-Permissions-Opt attribute for an API that you would like to access. If the API is not available, this call won't affect your app.
Your application must have the appropriate signed certificate to allow access to restricted APIs. Here are the JAD Certificate attributes:
For more information, refer to Java Application Security. You can also read more about MIDP 2.0 attributes on the Java ME site.
AT&T Developer Support recommends using OTA (over the air) to download and install your JavaME apps instead of side-loading (i.e., using a USB cable tethered between your computer and the device).
The biggest reason to avoid side-loading is that the device's JVM will place the app in the MIDP 1.0 sandbox. This will prevent your app from accessing MIDP 2.0 JSRs, which will leave your app without many types of robust functionality.
Moreover, there are certain types of bugs that are only discoverable when apps are OTA-loaded, rather than side-loaded, onto devices. Make sure to test the user experience in OTA-loaded versions of your app to avoid user complaints about bugs that were not discovered pre-launch.
Last but not least, AT&T has found that on some devices, an AT&T-signed Java ME app will not install via side-loading; the device does not recognize the signature, and there is no workaround to install the app.
Therefore, always use OTA to deliver your Java ME apps and games. Here's the MIME type you need to configure on your server in order to deliver apps OTA:
text/vnd.sun.j2me.app-descriptor jad
application/java-archive jar
In today's marketplace, mobile devices are required to perform many of the same operations as the traditional laptop or desktop. Many mobile applications today are network-aware or have access to sensitive user data such as documents or the information in phone books and calendars. To safeguard MIDP 2.0 has created the concept of protected domains. These domains have the same names as the functions or APIs that fall under each domain's umbrella. To enable the usage of these secure functions, a developer must request the domain within the JAD and .MF Manifest file. Java ME requires the use of the following parameters:
MIDlet-Permissions: parameter denotes functionality that is a necessary part of the application
and
MIDlet-Permissions-opt: parameter denotes functionality that may be required by the application during runtime, but is not vital to the operation
Java ME has a two-step installation process. During installation, the JAD parameters are reviewed. At this point, the Application Manager will look at request permissions and determine if such permissions can be granted to the application. If such permissions cannot be granted, the Application Manager will refuse to install the application if the functionality is required. Optional permissions not granted will still allow installation. This check is completed in order to keep the user from incurring data charges for the much larger JAR file.
If all permissions are granted, or defined as optional, the Application Manager will proceed to JAR delivery, at which time it will take the next step and review the requested permissions within the Manifest File. Once again, if such permissions cannot be granted, the Application Manager will refuse to install the application. Optional permissions not granted will still allow installation.
Secure functionality not requested at install time is denied during runtime by throwing a security error, or defaulting to access denied prompting behavior.
HTTP connectivity falls within the javax.microedition.io.Connector.http domain. In order to request this functionality, the following parameters should be added to JAD and Manifest at build time:
MIDlet-Permissions: javax.microedition.io.Connector.http
Without this permission, the application will most likely install, but networking connectivity may be arbitrarily denied at runtime of the application.
Please note that prompting behavior will vary depending on the Certificate used to sign the application. Unsigned builds will default to the MIDP 1.0 security policies. For Full information on AT&T specifications, please refer to Java Signing Specification. For Specific JSR documentation with the JCP.
For more information, please refer to the Sun Microsystems article Understanding MIDP 2.0's Security Architecture.
One of the major challenges when deploying an application is maintaining all of the separate builds for each device. A build constitutes a unique JAD/JAR combination. This becomes much more difficult after an application is signed. The signature inside the JAD file references a secure hash of the JAR file. If any aspect of the file changes, even a simple text string, the secure hash will change, and, therefore, an application would need to be resigned. If you add demos, locality builds, or different versions for a particular device, the number of builds could increase exponentially.
One way to manage a large number of builds is to add flexibility into your deployment model. Instead of hard-coding application parameters, package applications in a way that allows versatility.
You can accomplish this by using custom JAD parameters. Although the JAR file cannot be altered once the JAD/JAR pair is signed, the JAD file, being a text-based file, can be altered as long as the required parameters pointing to original JAR file are not changed. The certificate data, the secure hash, and application information should not be altered.
You can manually build multiple versions of JADs for deployment by either opening them in a
text editor and adding a line, or using a server-based programming language such as PHP, ASP,
or JSP to inject a line into the JAD file. If you decide on the server- injection method,
please make sure to use the appropriate mime-type:
'text/vnd.sun.j2me.app-descriptor.'
For example:
An application contains code to display the Subscriber's ID.
Add a custom parameter to the JAD file:
subID: inject variable using php, jsp, asp, etc.
Within the application code, request the value:
String subID = getAppProperty("subID");
The variable subID can now be used within the code; this will work whenever a
mutable value is needed.
Please note: when manually creating a file for deployment, follow all relevant JAD rules and be aware of supported characters. Please do not leave any metadata, non-supported characters, blank entries, or code segments within the JAD file. If you do, the file will fail on download.
For specific documentation, please refer to JSR-118. For more information, please refer to Sun's article, Retrieving Midlet Attributes.
The entire telecommunications industry is moving toward enabling security through the use of electronic certificates. Web sites rely on certificates to protect the privacy of their e-commerce transactions, and operating systems are using code-signing certificates to identify the source of packages and assign rights.
The major question asked is, "How does code signing help my customers?" The first thing that it does is ensure that customers are getting what they expect to download. When an application is signed, it cannot be changed in any way without invalidating that signing event. The customer knows that the application has come directly from the source without any tampering.
It is a simple task to create a fake application by using the graphics, text, and media from a company and then packaging a convincing skinned application that appears to be from that company. Without security in place to block access to critical areas such as personal data or network access, a consumer may be exploited because of the trust that the consumer had in a company's name. In the mobile industry, where the names of providers mean so much, it is imperative to do everything to protect these names and the trust that the consumer holds in these companies.
Once the source is known and trusted, certain privileges can be extended to your customers. All application platforms supporting security models will prompt the user when the source of the application is unsigned; by signing, however, these simple "untrusted" messages will disappear. This is good practice to follow even for applications that do not require secure APIs to function correctly. The message goes away at install, and customers seamlessly access the product.
The final benefit that can be offered after trust is established is a limit to prompting behavior. An unsigned application will prompt the customer with every network action, whereas a third-party signed application will only prompt once during the session.
When used correctly, code signing can protect your name and your customers' privacy.
Source: Amitava Bhattacharyya, Development Lead, TeleNav. Inc.
Bluetooth API JSR-82
The Java APIs for Bluetooth define the following package that depends on the CLDC
javax.microedition.io package:
javax.bluetooth: core Bluetooth APIThe above package is a separate optional package, which means that a CLDC implementation can include either package or both. MIDP-enabled devices are expected to be the kind of devices to incorporate this specification.
The anatomy of a Bluetooth application has five parts: stack initialization, device management, device discovery, service discovery, and communication.
The Bluetooth stack is responsible for controlling the Bluetooth device. The initialization process comprises a number of steps whose purpose is to get the device ready for wireless communication.
The Java Bluetooth APIs contain the classes LocalDevice and
RemoteDevice, which provide the device-management capabilities defined in the
Generic Access Profile. LocalDevice depends on the
javax.bluetooth.DeviceClass class to retrieve the device's type and the kinds of
services it offers. The RemoteDevice class represents a remote device (a device
within a range of reach) and provides methods to retrieve information about the device,
including its Bluetooth address and name. The following code snippet retrieves that information
for the local device:
|
... // retrieve the local Bluetooth device object LocalDevice local = LocalDevice.getLocalDevice(); // retrieve the Bluetooth address of the local device String address = local.getBluetoothAddress(); // retrieve the name of the local Bluetooth device String name = local.getFriendlyName(); ... |
You can get the same information about a remote device:
|
... // retrieve the device that is at the other end of // the Bluetooth Serial Port Profile connection, // L2CAP connection, or OBEX over RFCOMM connection RemoteDevice remote = RemoteDevice.getRemoteDevice( javax.microedition.io.Connection c); // retrieve the Bluetooth address of the remote device String remoteAddress = remote.getBluetoothAddress(); // retrieve the name of the remote Bluetooth device String remoteName = local.getFriendlyName(true); ... |
The RemoteDevice class also provides methods to authenticate, authorize, or
encrypt data transferred between local and remote devices.
Because wireless devices are mobile they need a mechanism that allows them to find other
devices and gain access to their capabilities. The core Bluetooth API's
DiscoveryAgent class and DiscoveryListener interface provide the
necessary discovery services.
A Bluetooth device can use a DiscoveryAgent object to obtain a list of
accessible devices, in any of three ways:
The DiscoveryAgent.startInquiry method places the device into an inquiry mode.
To take advantage of this mode, the application must specify an event listener that will
respond to inquiry-related events. DiscoveryListener.deviceDiscovered is called
each time an inquiry finds a device. When the inquiry is completed or canceled,
DiscoveryListener.inquiryCompleted is invoked.
If the device doesn't wish to wait for devices to be discovered, it can use the
DiscoveryAgent.retrieveDevices method to retrieve an existing list. Depending on
the parameter passed, this method will return either a list of devices that were found in a
previous inquiry, or a list of pre-known devices that the local device has told the
Bluetooth Control Center it will contact often.
These three code snippets demonstrate the various approaches:
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // place the device in inquiry mode boolean complete = agent.startInquiry(); ... |
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // return an array of pre-known devices RemoteDevice[] devices = agent.retrieveDevices(DiscoveryAgent.PREKNOWN); ... |
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // return an array of devices found in a previous inquiry RemoteDevice[] devices = agent.retrieveDevices(DiscoveryAgent.CACHED); ... |
Once the local device has discovered at least one remote device, it can begin to search for
available services—Bluetooth applications it can use to accomplish useful tasks.
Because service discovery is much like device discovery, DiscoveryAgent also
provides methods to discover services on a Bluetooth server device, and to initiate
service-discovery transactions. Note that the API provides mechanisms to search for services on
remote devices, but not for services on the local device.
For a local device to use a service on a remote device, the two devices must share a common communications protocol. So that applications can access a wide variety of Bluetooth services, the Java APIs for Bluetooth provide mechanisms that allow connections to any service that uses RFCOMM, L2CAP, or OBEX as its protocol. If a service uses another protocol (such as TCP/IP) layered above one of these protocols, the application can access the service, but only if it implements the additional protocol in the application, using the CLDC Generic Connection Framework.
The RFCOMM protocol, which is layered over the L2CAP protocol, emulates an RS-232 serial connection. The Serial Port Profile (SPP) eases communication between Bluetooth devices by providing a stream-based interface to the RFCOMM protocol. Some capabilities and limitations to note:
For a server and client to communicate using the Serial Port Profile, each must perform a few simple steps.
As the following code snippet demonstrates, the server must:
The URL placed in the service record may look something like:
btspp://102030405060740A1B1C1D1E100:5
This says that a client should use the Bluetooth Serial Port Profile to establish a connection to this service, which is identified with server channel 5 on a device whose address is 102030405060740A1B1C1D1E100.
|
... // assuming the service UID has been retrieved String serviceURL = "btspp://localhost:"+serviceUID.toString()); // more explicitly: String ServiceURL = "btspp://localhost:10203040607040A1B1C1DE100;name=SPP Server1"; try { // create a server connection StreamConnectionNotifier notifier = (StreamConnectionNotifier) Connector.open(serviceURL); // accept client connections StreamConnection connection = notifier.acceptAndOpen(); // prepare to send/receive data byte buffer[] = new byte[100]; String msg = "hello there, client"; InputStream is = connection.openInputStream(); OutputStream os = connection.openOutputStream(); // send data to the client os.write(msg.getBytes()); // read data from client is.read(buffer); connection.close(); } catch(IOException e) { e.printStackTrace(); } ... |
At the other end, as the next code snippet shows, to set up an RFCOMM connection to a server the client must:
|
... // (assuming we have the service record) // use record to retrieve a connection URL String url = record.getConnectionURL( record.NOAUTHENTICATE_NOENCRYPT, false); // open a connection to the server StreamConnection connection = (StreamConnection) Connector.open(url); // Send/receive data try { byte buffer[] = new byte[100]; String msg = "hello there, server"; InputStream is = connection.openInputStream(); OutputStream os = connection.openOutputStream(); // send data to the server os.write(msg.getBytes); // read data from the server is.read(buffer); connection.close(); } catch(IOException e) { e.printStackTrace(); } ... |
How to read GPS data from Bluetooth stream
readBluetoothBuffer()
{
data = readAllAvailableBytes()
if (data.length == 0)
Bluetooth connection not there
else
Bluetooth seems OK
bytesRead = readBytes();
if (no bytesRead)
read error
else
START Loop
find newLine()
{
//figure out whether it's RMC or GGA
String candidate = readBuffer
//figure out whether RMC or GGA
if (candidate is $GPRMC....)
{
Store candidate as RMC
}
else if (candidate is $GPGGA)
{
Store candidate as GGA
}
}
END Loop
}
Common NMEA Sentence types
The following information describes the NMEA-0183 sentences transmitted by TeleType GPS receivers.
| $GPGGA | Global positioning system fixed data |
| $GPGLL | Geographic position - latitude / longitude |
| $GPGSA | GNSS DOP and active satellites |
| $GPGSV | GNSS satellites in view |
| $GPRMC | Recommended minimum specific GNSS data |
| $GPVTG | Course over ground and ground speed |
This document is based upon my personal experience, knowledge and several documents freely available on the Internet.
With MIDP 2.0, devices often have limited resources. Because these devices do not possess native libraries for displaying XML, HTML or xHTML code, we have found that it is often easier to use the device browser to enable Web-based browsing sessions than to have the Java application scrape the code. Invoking Platform Services in a MIDP 2.0 Java application allows a request to the Web browser as well as to additional external services like the telephone dialer or a downloadable resource. The Platform Request is a MIDP2.0 non-blocking API that will take into account device resources. This API is available on most MIDP 2.0 devices including Nokia, Motorola, and Sony Ericcson.
To access a Web browser within your Java application, try this sample code:
//Code Snippet
private void openBrowser(String URL) {
try {
if ( platformRequest(URL) ) {
//If true application
//needs to close prior
//to opening browser.
//Add any clean up code here,
//such as warnings that
//application will terminate,
//garbage collection, and
//saving state data.
destroyApp(false);
notifyDestroyed();
}
else {
//If false application
//does not need to close
//prior to launch of browser.
//Handle any pause information
//at this point because the
//application will lose focus
}
//Clean up
}
catch(ConnectionNotFoundException e) {
//Error is thrown if connection is not available
}
}
//End Code Snippet
For more information on Platform Request, read Invoking Platform Services in MIDP 2.0 on the Sun Developer Network.
Source: Amitava Bhattacharyya, Development Lead, TeleNav. Inc.
The Java APIs for Bluetooth define the following package that depends on the CLDC
javax.microedition.io package:
javax.bluetooth: core Bluetooth APIThe above package is a separate optional package, which means that a CLDC implementation can include either package or both. MIDP-enabled devices are expected to be the kind of devices to incorporate this specification.
The anatomy of a Bluetooth application has five parts: stack initialization, device management, device discovery, service discovery, and communication.
The Bluetooth stack is responsible for controlling the Bluetooth device. The initialization process comprises a number of steps whose purpose is to get the device ready for wireless communication.
The Java Bluetooth APIs contain the classes LocalDevice and
RemoteDevice, which provide the device-management capabilities defined in the
Generic Access Profile. LocalDevice depends on the
javax.bluetooth.DeviceClass class to retrieve the device's type and the kinds of
services it offers. The RemoteDevice class represents a remote device (a device
within a range of reach) and provides methods to retrieve information about the device,
including its Bluetooth address and name. The following code snippet retrieves that information
for the local device:
|
... // retrieve the local Bluetooth device object LocalDevice local = LocalDevice.getLocalDevice(); // retrieve the Bluetooth address of the local device String address = local.getBluetoothAddress(); // retrieve the name of the local Bluetooth device String name = local.getFriendlyName(); ... |
You can get the same information about a remote device:
|
... // retrieve the device that is at the other end of // the Bluetooth Serial Port Profile connection, // L2CAP connection, or OBEX over RFCOMM connection RemoteDevice remote = RemoteDevice.getRemoteDevice( javax.microedition.io.Connection c); // retrieve the Bluetooth address of the remote device String remoteAddress = remote.getBluetoothAddress(); // retrieve the name of the remote Bluetooth device String remoteName = local.getFriendlyName(true); ... |
The RemoteDevice class also provides methods to authenticate, authorize, or
encrypt data transferred between local and remote devices.
Because wireless devices are mobile they need a mechanism that allows them to find other
devices and gain access to their capabilities. The core Bluetooth API's
DiscoveryAgent class and DiscoveryListener interface provide the
necessary discovery services.
A Bluetooth device can use a DiscoveryAgent object to obtain a list of
accessible devices, in any of three ways:
The DiscoveryAgent.startInquiry method places the device into an inquiry mode.
To take advantage of this mode, the application must specify an event listener that will
respond to inquiry-related events. DiscoveryListener.deviceDiscovered is called
each time an inquiry finds a device. When the inquiry is completed or canceled,
DiscoveryListener.inquiryCompleted is invoked.
If the device doesn't wish to wait for devices to be discovered, it can use the
DiscoveryAgent.retrieveDevices method to retrieve an existing list. Depending on
the parameter passed, this method will return either a list of devices that were found in a
previous inquiry, or a list of pre-known devices that the local device has told the
Bluetooth Control Center it will contact often.
These three code snippets demonstrate the various approaches:
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // place the device in inquiry mode boolean complete = agent.startInquiry(); ... |
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // return an array of pre-known devices RemoteDevice[] devices = agent.retrieveDevices(DiscoveryAgent.PREKNOWN); ... |
|
... // retrieve the discovery agent DiscoveryAgent agent = local.getDiscoveryAgent(); // return an array of devices found in a previous inquiry RemoteDevice[] devices = agent.retrieveDevices(DiscoveryAgent.CACHED); ... |
Service Discovery
Once the local device has discovered at least one remote device, it can begin to search for
available services - Bluetooth applications it can use to accomplish useful tasks.
Because service discovery is much like device discovery, DiscoveryAgent also
provides methods to discover services on a Bluetooth server device, and to initiate
service-discovery transactions. Note that the API provides mechanisms to search for services on
remote devices, but not for services on the local device.
For a local device to use a service on a remote device, the two devices must share a common communications protocol. So that applications can access a wide variety of Bluetooth services, the Java APIs for Bluetooth provide mechanisms that allow connections to any service that uses RFCOMM, L2CAP, or OBEX as its protocol. If a service uses another protocol (such as TCP/IP) layered above one of these protocols, the application can access the service, but only if it implements the additional protocol in the application, using the CLDC Generic Connection Framework.
The RFCOMM protocol, which is layered over the L2CAP protocol, emulates an RS-232 serial connection. The Serial Port Profile (SPP) eases communication between Bluetooth devices by providing a stream-based interface to the RFCOMM protocol. Some capabilities and limitations to note:
For a server and client to communicate using the Serial Port Profile, each must perform a few simple steps.
As the following code snippet demonstrates, the server must:
The URL placed in the service record may look something like:
btspp://102030405060740A1B1C1D1E100:5
This says that a client should use the Bluetooth Serial Port Profile to establish a connection to this service, which is identified with server channel 5 on a device whose address is 102030405060740A1B1C1D1E100.
|
... // assuming the service UID has been retrieved String serviceURL = "btspp://localhost:"+serviceUID.toString()); // more explicitly: String ServiceURL = "btspp://localhost:10203040607040A1B1C1DE100;name=SPP Server1"; try { // create a server connection StreamConnectionNotifier notifier = (StreamConnectionNotifier) Connector.open(serviceURL); // accept client connections StreamConnection connection = notifier.acceptAndOpen(); // prepare to send/receive data byte buffer[] = new byte[100]; String msg = "hello there, client"; InputStream is = connection.openInputStream(); OutputStream os = connection.openOutputStream(); // send data to the client os.write(msg.getBytes()); // read data from client is.read(buffer); connection.close(); } catch(IOException e) { e.printStackTrace(); } ... |
At the other end, as the next code snippet shows, to set up an RFCOMM connection to a server the client must:
|
... // (assuming we have the service record) // use record to retrieve a connection URL String url = record.getConnectionURL( record.NOAUTHENTICATE_NOENCRYPT, false); // open a connection to the server StreamConnection connection = (StreamConnection) Connector.open(url); // Send/receive data try { byte buffer[] = new byte[100]; String msg = "hello there, server"; InputStream is = connection.openInputStream(); OutputStream os = connection.openOutputStream(); // send data to the server os.write(msg.getBytes); // read data from the server is.read(buffer); connection.close(); } catch(IOException e) { e.printStackTrace(); } ... |
How to read GPS data from Bluetooth stream
Code snippet
readBluetoothBuffer()
{
data = readAllAvailableBytes()
if (data.length == 0)
Bluetooth connection not there
else
Bluetooth seems OK
bytesRead = readBytes();
if (no bytesRead)
read error
else
START Loop
find newLine()
{
//figure out whether it's RMC or GGA
String candidate = readBuffer
//figure out whether RMC or GGA
if (candidate is $GPRMC....)
{
Store candidate as RMC
}
else if (candidate is $GPGGA)
{
Store candidate as GGA
}
}
END Loop
}
Common NMEA Sentence types
The following information describes the NMEA-0183 sentences transmitted by TeleType GPS receivers.
| Sentence | Description |
| $GPGGA | Global positioning system fixed data |
| $GPGLL | Geographic position - latitude / longitude |
| $GPGSA | GNSS DOP and active satellites |
| $GPGSV | GNSS satellites in view |
| $GPRMC | Recommended minimum specific GNSS data |
| $GPVTG | Course over ground and ground speed |
This document is based upon my personal experience, knowledge and several documents freely available on the internet.
JSR 211, or the Content Handler API (CHAPI), lets you specify MIDlets as content handlers for one or more specific file types. It enables MIDlet invocation from a variety of sources, including a MIDlet, a browser, or an SMS message. AT&T is requiring JSR 211 support in all mid-range and high-end devices coming down the pipeline.
As you're getting started with JSR 211, it's important to be aware that you can utilize the system property microedition.chapi.version to determine whether or not CHAPI is implemented in the system, and if so, what the version number is.
The code resides in the javax.microedition.content package and is fairly straightforward to use. You can register your MIDlet as a content handler in one of two ways: either by using .jad attributes or by registering dynamically in Java.
Using .jad attributes is called a .jad register, and that is the focus of this Tech Tip. (We'll cover MIDlet registers in the next part of this Tech Tip series of Tech Tips.)
To set up your MIDlet as a content handler, you can include these .jad attributes, but only the first one, MicroEdition-Handler-<n>, is required.
MicroEdition-Handler-<n>: <classname>, <type(s)>, <suffix(es)>, <action(s)>, <locale(s)>
These attributes describe the handlers included in the MIDlet Suite. The arguments are the name of the MIDlet responsible for handling the content, the supported MIME-types, the supported suffixes, the supported actions (such as "open" or "edit"), and the locales.
MicroEdition-Handler-<n>-<locale>: <localized action names>
This .jad attribute stores the descriptive names of the actions. Applications can retrieve these names using the ActionNameMap class. The list is typically useful for exhibition on the user interface. The locale suffix associates different languages (en-US, br-PT, etc.) and enables the handler to be globalized.
MicroEdition-Handler-<n>-ID: <ID>
This attribute specifies the unique identifier of this content handler package on the device. You don't have to supply the identifier, because the underlying implementation should create it.
MicroEdition-Handler-<n>-Access: <ID(s)>
This attribute controls the access and visibility of the content handler. It contains a list of the IDs of content handlers or applications that are allowed access and visibility into the content handler. If this attribute is omitted, all applications will be allowed access and visibility into the content handler.
Here's a little example demonstrating how you could set up a MIDlet to be a .png content handler:
MicroEdition-Handler-1: example.imageviewer.ImageViewer, image/png, .png, open, en-US fr MicroEdition-Handler-1-en-US: Open MicroEdition-Handler-1-fr: Voir MicroEdition-Handler-1-ID: com.sun.example.imageviewer MicroEdition-Handler-1-Access: com.sun.example
Java Commands provide an easy and quick way to get user input from a MIDlet that is using LCDUI. When utilizing the Command class, it is important to note that the Commands only capture the intent of the action, not the action itself. The action itself is captured in a CommandListener.
Commands can be utilized in any UI element that is set up to activate an actionthink buttons, menu items, radio buttons, etc. Commands contain four parameters: a short label, a long label (optional), a type, and a priority. The label parameters are self-explanatory. The type parameter specifies what action a Command should initialize. The standard types are back, cancel, exit, help, item, OK, screen, and stop. The priority parameter describes the Command's importance relative to other Commands.
Here is a small sample MIDlet which demonstrates the use of an exit command:
package com.att;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class MIDletCommands extends MIDlet implements CommandListener {
private Command commandExit;
private Display display;
public MIDletCommands() {
display = Display.getDisplay( this);
commandExit = new Command("Exit", Command.EXIT, 1);
}
//Create text box and add the command.
public void startApp() {
TextBox tb = new TextBox("MIDletCommands", "MIDletCommands ", 256, 0 );
tb.addCommand( commandExit );
tb.setCommandListener( this );
display.setCurrent( tb );
}
public void pauseApp() {}
public void destroyApp( boolean unconditional ) {}
//This is where the app should respond to commands.
public void commandAction( Command command, Displayable disp ) {
if ( command == commandExit ) {
destroyApp( false );
notifyDestroyed();
}
}
}
JSR 179, or the Location API, gives developers the means to harness one of the most important and powerful capabilities in a mobile device¿it always knows where it is. This API, contained in the javax.microedition.location package, retrieves a device's location in a consistent, standardized fashion using the geospatial coordinates of latitude, longitude, and altitude. Latitude values range from 0 - 90 degrees north or south of the equator; longitude values range from 0 - 180 degrees east or west of the Prime Meridian, marked at Greenwich, England (UK).
Note: To protect the privacy and security of our mobile subscribers, AT&T opens access to the Location API only to developers who have established a trusted business relationship with AT&T. If you are interested in using the Location API and would like to become a trusted AT&T partner, begin the certification process.
How to use JSR 179To use JSR 179, you must first create a Criteria object. The Criteria object can contain such characteristics as latency, speed, need for altitude, and accuracy. Here's some code that demonstrates creating a Criteria object:
// Sets horizontal accuracy to 20m. Criteria criteria = new Criteria(); criteria.setHorizontalAccuracy( 20 );
After you build your Criteria object, you must create a location provider using that object:
LocationProvider locationProvider = LocationProvider.getInstance( criteria );
And finally, here's how to get the actual location of the mobile device:
// Sets a 2 minute timeout Location location = locationProvider.getLocation( 120 ); Coordinates coordinates = location.getQualifiedCoordinates();
if( coordinates != null ) {
// Get latitude & longitude
double latitude = coordinates.getLatitude();
double longitude = coordinates.getLongitude();
}
MIDlet class: startApp(), pauseApp(), and destroyApp().
package com.att;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloWorldMIDlet extends MIDlet {
//kv Constructor
public HelloWorldMIDlet() {}
public void startApp() {
Canvas canvas = new HelloWorldCanvas();
Display display = Display.getDisplay( this );
display.setCurrent( canvas);
}
public void pauseApp() {}
public void destroyApp( boolean unconditional ) {}
}
class HelloWorldCanvas extends Canvas {
public void paint( Graphics g ) {
g.setColor( 255, 255, 255 );
g.drawString("Hello World!", 0, 0, g.TOP | g.LEFT);
}
}
JSR 179, or the Location API, can be a bit tricky to master because of device-specific differences in not only the hardware implementations of the GPS functionality, but also in the software implementations. On the software side, much of the confusion lies around setting up your Criteria object properly because some devices allow you to set certain criteria while others don't. This inconsistency can be a puzzle; in some cases it may be impossible to write code that will work on all devices.
To alleviate some of the challenge with JSR 179, make sure first and foremost that your app is signed with an AT&T Trusted certificate. This will prevent any security exceptions. (If you are interested in using location APIs and would like to become an AT&T trusted partner, learn about and begin the certification process.)
Secondly, if your LocationProvider.getInstance() method is returning null, your target device may not support some of the criteria that you're attempting to set. In order to debug this, we recommend starting with the most basic setup; that is, instantiating your LocationProvider with a default Criteria object like so:
Criteria criteria = new Criteria(); LocationProvider locationProvider = LocationProvider.getInstance( criteria );
After you've verified that this most basic setup works, you can go about fine-tuning your Criteria object and experimenting with which criteria settings work and which don't. Here's an example of setting the criteria for assisted and autonomous GPS modes:
// Assisted GPS mode cr.setHorizontalAccuracy( 500 ); cr.setVerticalAccuracy( 500 ); cr.setPreferredPowerConsumption( Criteria.NO_REQUIREMENT ); // Autonomous GPS mode //cr.setHorizontalAccuracy( Criteria.NO_REQUIREMENT ); //cr.setVerticalAccuracy( Criteria.NO_REQUIREMENT ); //cr.setCostAllowed( false ); //cr.setPreferredPowerConsumption( Criteria.POWER_USAGE_MEDIUM );
Be very wary with the setHorizontal() and setVertical() methods, as some devices will return a null LocationProvider if the horizontal or vertical criteria are set to less than a certain threshold. For example, the Samsung Rugby II (SGH-A847) returns a null LocationProvider if the horizontal or vertical criteria is set to less than 100 meters. The Rugby II will also return a null LocationProvider if setCostAllowed() is set to false.
Along these same lines, some devices like the Rugby II may not support getHorizontalAccuracy() and getVerticalAccuracy(). They will simply return null for these methods even if the Criteria object is set up with the default values for horizontal and vertical accuracy.
Finally, it's important to keep in mind that acquiring location in mobile apps is still a work in progress. Because location is not yet an exact science, don't expect to be able to get exact measurements. Measurements within 10 meters are well within the accuracy thresholds for GPS. It's also prudent to expect that your measurements may jump around a bit; you can smooth out your measurements by taking averages over time and throwing out the outliers.
J2ME applications connecting through the WAP gateway may be tested against the AT&T
developer gateway from the BlackBerry JDE.
WAP applications connecting through the WAP gateway must be tested using a production-quality
device against the production wireless network.
Configuring the BlackBerry Simulator for the AT&T Test Gateway
If you are testing applications that require an HTTP connection, you must first start the Mobile Data Service simulator:
Command line options are then set to configure the simulator to work with a test gateway:
In the Simulator Command line field, add options after the OsLoader.exe OsHh3G.d11
entry.
The following command line options enable the simulator to connect to test gateways:
The architecture of the Java programming language holds the promise of applications that you
can "write once, run anywhere." In reality, however, Java ME (the version of Java scaled down
for wireless devices) comes installed in a diverse array of devices. From custom OEM extensions
to variances in screen size, most J2ME developers often have to "write once, run once" (or at
least on only one device). Although you may not be able to completely re-use your code, there
are few architectural decisions about relative positioning versus absolute positioning that you
can make up front to simplify porting your applications to other devices later.
Devices have different application size limitations. Decide with your team up front which
features you would remove if you had to make your application much smaller. Clearly segregate
and comment your code so that these features can be easily identified and removed later.
Use relative positioning when you draw objects rather than absolute positioning.
Where possible, use one component of your MIDlet suite to hold the specific properties for each
device, so that your logic and presentation can be managed separately.
It may even be possible to create a dynamic JAD file that grabs the UA Profile from the HTTP
header and writes a custom attribute for the screen size for that device. You can store these
values in the RMS and access them programmatically from within the MIDlet suite.
Always keep in mind that you may want to port your wireless application later, even if you
don't think so now. Planning for this up front can save you time later!