Take the High Road when Creating MIDP User Interfaces

ne of the biggest challenges of writing software for mobile devices is creating user interfaces that work across a number of devices. As an application is deployed from device to device, developers face challenges due to changing environment parameters and device specifications. Screen sizes and pixel resolutions vary. Some devices are monochrome, while others support color. Some devices have two softkeys (keys on the device keypad that map to application commands) for user input, others have three?or perhaps one softkey and a scroll wheel to move through a list of options.

MIDP strives to solve these problems by providing a framework and a collection of user interface controls. These user interface APIs are found in the javax.microedition.lcdui package.

What You Need: Wireless Toolkit 2.1. Available at: http://java.sun.com/products/j2mewtoolkit/download-2_1.html.

Mobile Devices Are Not Desktop Computers
The MIDP user interface specifications differ greatly from what is found in the AWT or Swing APIs of J2SE. The primary reason for this is that mobile devices have different constraints, and therefore users interact with mobile devices differently than with desktop computers. For example, a cell phone does not have a mouse, or similar pointing device to guide user interactions. Most likely, a user will be limited to a fairly small screen, a 10-digit input keypad, and a few other keys to aid in selecting items from a list or invoking some type of command.

Furthermore, most MIDP-class devices do not support running multiple applications simultaneously, or even the ability to have multiple application windows open at the same time. For this reason, the MIDP user interface API diverges from standard Java in order to better support more limited devices.

High-Level and Low-Level APIs
The MIDP user interface specification divides the javax.microedition.lcdui APIs into two categories: high-level and low-level. The high-level APIs are where the pre-built components live. In here you will find classes such as List, Form, and TextField, among others.

These components are often your best bet for porting the user interface portion of your application between devices without modification. This is because each device implementation is responsible for mapping the behavior of these components as needed for the device. In some cases, the left and right softkeys may be reversed between devices, or some lists may have different List line wrapping logic. This allows MIDP applications to behave like other applications running on the same device and adhere to the same set of user interface guidelines defined by the device manufacturer. In short, the MIDP high-level user interface APIs are designed to provide a consistent interface for applications while allowing some malleability between platforms.

The low-level APIs in MIDP make no such promise as far as portability is concerned. The low-level APIs provide a rich set of fine-grained user interface control. This is where classes such as Canvas live. Using a Canvas, developers can create just about anything they wish. The downside is that developers are also responsible for handling the portability issues between devices. Seemingly simple things become issues, such as the display writing off the edge of the screen, or only using an upper left portion screen and leaving the lower right empty. It is likely that a low-level user interface will also need to handle different key mappings to perform the same tasks between devices. For example, on device A an application might trap a key press event for key 35 to select an item from a list, where on device B the application may need to look for key 12.

Although MIDP does provide some help in managing low-level APIs between devices, the recommended practice is to use the high-level APIs whenever possible. In this month’s article I will focus on the high-level APIs. Next month, I will circle back and talk more about the low-level APIs.

Using the MIDP User Interface Classes
Regardless of whether an application makes use of the high or low-level APIs, there are some core classes that are always needed. One of these classes is Display. Display allows access to a device’s display mechanism. The following code demonstrates how to gain access to the display.

Display theDisplay = Display.getDisplay(myMidlet);

The call to getDisplay() requires a reference to the current MIDlet. An instance of the device display context is returned. An application uses the Display instance to show a screen on the device:

theDisplay.setCurrent(myDisplay);

or to query the display instance to find out what screen is currently shown.

Displayable currentScreen = theDisplay.getCurrent();

Another class that makes up the MIDP user interface framework is Displayable. Displayable is an abstract class that forms the basis for what can set as the current display. It is in the subclasses of Displayable that high-level and low-level APIs diverge. Figure 1 illustrates this divergence.

Figure 1. The Top-most Part of the javax.microedition.lcdui Class Hierarchy: The diagram shows the split between the high-level and low-level APIs.

The Screen Class
As shown in Figure 1, the Screen class is where the high-level UI begins. Because Screen is a subclass of Displayable, instances can be passed to Display.setCurrent(). When this occurs, the instance becomes the currently visible display and consumes the entire display. There are four different types of Screens: Form, List, TextBox, and Alert. Each one of these is discussed in detail in this article, beginning with TextBox.

TextBox
TextBox is a type of Screen that is used for text entry. A TextBox can be configured to use Input Constraints in order to provide some built-in validation and formatting of the data associated with the control. For example, setting the constraints of a TextBox to TextBox.NUMERIC tells the TextBox to only accept numbers in the field. An input constraint such as NUMERIC also will prevent the keypad from cycling through the non-numeric characters.

Using the PHONENUMBER constraint tells MIDP that the data is a phone number. If the device supports making phone calls, using this constraint can provide the ability to initiate a phone call when the field has focus.

Table 1 is a list of constraints that apply to TextBox:

Table 1. A TextBox can be configured to validate user input based on any of these built-in constraints.

Constraint

Description

ANY

alphanumeric

NUMERIC

numbersonly

EMAILADDR

emailaddress format

PHONENUMBER

phonenumber format

URL

URL format

DECIMAL

positiveand negative real numbers

Modifier flags can be added in conjunction with the input constraints using the bitwise “|” operator (OR). For example ANY | PASSWORD would allow alphanumeric entry into a TextBox and the input characters would be masked with a character such as an asterisk (*). Table 2 lists available modifier flags.

Table 2. These modifier flags can be used with the constraints in Table 1 to improve data validation and user experience.

Modifier

Description

PASSWORD

Masks input with a character such as an asterisk (*).

UNEDITABLE

Makes the TextField or TextBox read only.

SENSITIVE

Used to let the underlying implementation know that the data being entered is sensitive and should not be added to predictive databases for quick entry, etc. A credit card number is an example of such data.

NON_PREDICTIVE

Used to let the underlying implementation know that predictive prompting to assist user input should not be used. This is helpful in cases where the data is unlikely to exist in a predictive text database on a device.

INITIAL_CAPS_WORD

Indicates that the first letter of each word should be capitalized.

INITIAL_CAPS_SENTENCE

Indicates that the first letter of the first word of each sentence should be capitalized.

Figure 2 shows an example of a TextBox as the current display.

Figure 2. Example of a TextBox as the Current Display: Note that the label is set to “TextBox Example:”

Lists, Alerts, and Forms
List
The List control is used to display collections of information. List has three modes: IMPLICIT, EXCLUSIVE, and MULTIPLE. The EXCLUSIVE mode allows only one item to be selected at a time, such as with a group of radio buttons. The MULTIPLE mode allows multiple items to be selected, such as with a group of checkboxes. The IMPLICIT mode is similar to a menu. When a row is selected the application responds by performing some type of action. Figure 3 shows the same list displayed in different modes.

Figure 3. Examples of a List: : The list contains three rows where the third row wraps across lines and is the currently highlighted item. From left to right the modes are: IMPLICIT, EXCLUSIVE, and MULTIPLE.

Alert
Alerts are screens used in displaying messages to users. Generally an Alert will either be displayed for a specified duration of milliseconds or will wait until the user dismisses the message by pressing a button. The code snippet below displays an Alert and waits for the user to dismiss the message. When the OK command is selected, the application can respond to the command.

Alerts support multiple commands, so you can provide conditional prompts as well, allowing the user to respond to Yes/No or OK/Cancel type of questions. Figure 4 shows an Alert as the current display.

Command ok = new Command("OK", Command.ITEM, 1);Alert a = new Alert("Example Alert!");a.addCommand(ok);a.setTimeout(Alert.FOREVER);a.setCommandListener(this);a.setString("Hey, your fly is open!");Display.getDisplay(this).setCurrent(a); 

Figure 4. Example of an Alert: In this example a command is registered with the alert and the timeout is set to Alert.FOREVER. This means that the message will be displayed until the user presses the softkey associated with the “OK” command.
 
Figure 5. Class hierarchy of Item types: Classes inheriting from Item are intended to be placed onto a Form to create user interfaces. Items by themselves cannot become the current display. They must always reside within a Form.

Form
Form is a type of Screen that can contain a number user interface controls. The controls placed on a Form must inherit from Item. See Figure 5 for a class diagram of Items. Items are appended to a form using the Form.append() method. Table 3 describes the types of Items in more detail.

Table 3. Types of user interface controls that can be appended to a Form.

Item

Description

StringItem

Text display field. StringItem can only display text. The user can highlight StringItems but the content cannot be edited.

TextField

Text entry field for entering data. TextField has the same characteristics of TextBox except that TextField inherits from Item and is used within Forms. TextField supports the same Input Constraints as TextBox.

ChoiceGroup

ChoiceGroup supports the ability to make selection from a group of related options. ChoiceGroup supports making a single selection from a group, behaving like a group of radio buttons, or making multiple selections like a checkbox group.

DateField

DateFields are used for displaying and editing time and date information. This field has three settings, DATE, which deals only with the date portion, TIME, which deals only with time, and DATE_TIME, which deals with both date and time information in the same field.

ImageItem

ImageItem is used to display an image within a form.

Gauge

Gauge can be placed on a form to visually indicate progress.

Spacer

Spacer is a special type of form component that is used as part of the form layout policy to provide spacing between components. Since Spacer is an Item, it contains methods for adding Commands and a label. However, since Spacer is intended for positioning other components rather than user interaction, attempting to add a Command or label to a Spacer will throw an IllegalArgumentException.

CustomItem

CustomItem is new in MIDP 2.0 and provides a way for application developers to write their own Form controls. Prior to MIDP 2.0 there was no way to create a custom Item control. Unlike other Items, CustomItem also has the ability to trap keypress events, allowing applications to respond to more than just the softkey Commands.

Figure 6 shows an example of a form containing a few controls. The Gauge control uses Item.LAYOUT_RIGHT to right-justify the Gauge. Figure 7 shows the MIDP editors for date and time fields.

Form Layout Policy
Form supports only one layout policy; however, there are a number of directives that can be used to control the layout. The Form layout policy is similar to FlowLayout used by AWT. A form will attempt to place as many Items in a row as possible. When the next Item to display does not fit into the remaining space, the Item will be placed on the next row.

To fine-tune the layout, MIDP 2.0 contains a special Item called Spacer. Spacer is a non-interactive, “invisible” Item that aids in controlling a Form‘s layout. A number of directives can also be used to align Items to the right, center, or left as well as to shrink and expand Items to fill available space on the row. Layout directives are specified by constants in the Item class.


Figure 6. Multiple Controls: The example Form is displaying several different controls.
 
Figure 7. Setting the Time: Here’s the UI for editing date and time fields from a form. The user navigates to these views by selecting the or

Event Handling
The high-level MIDP 2.0 controls provide three ways to respond to user interactions. The most common is to create a Command. Commands generally display a label above one of the device softkeys. When the user presses the softkey, an event is fired and the application can respond appropriately.

Commands are available to any Displayable. When the Displayable is the current display, all issued Commands are directed to the CommandListener registered with the Displayable. CommandListener is an interface supporting the event handler method commandAction(). To set the CommandListener make a call to Displayable.setCommandListener(). There can be only one CommandListener for a Displayable at any given time.

If the application uses a Form, state changes can be monitored on an Item-by-Item basis using the ItemStateListener. When the user modifies an Item, a call to ItemStateListener.itemStateChanged() is made. The Item of interest is passed as a parameter. An ItemStateListener is registered with the Form and will be notified if any Items on the Form are changed.

As of MIDP 2.0, Forms have another method of interacting with users through the implementation of ItemCommandListener. Like CommandListener, ItemCommandListener defines a commandAction() method. The difference is that the ItemCommandListener is registered with the Item itself, rather than with the Form. This localizes the Command event response to the Item rather than making the Form handle event logic for all Items.

Finally! Portable UI Made Easy
Creating user interfaces that can be deployed to multiple devices without modification is a challenge for mobile software developers. The MIDP specification contains user interface APIs designed to address many portability issues. To take advantage of the designed-in portability of MIDP, developers are encouraged to use the high-level APIs whenever possible and practical.

The high-level APIs provide many out-of-the-box user interface features as well as help ensure the application user interface maps correctly from device to device. In some cases, however, the high-level APIs may be too limiting to provide the desired effect or capability needed by an application. These situations may call for using the low-level APIs. In next month’s article I will discuss using the low-level APIs and highlight some of the implementation trade-offs, benefits, and issues developers are likely to encounter.

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

Overview

Recent Articles: