The name, icon, and primary class, separated by commas, of each MIDlet in the suite. If there are three MIDlets in the suite, for example, the manifest has the three attributes: MIDlet-1, MIDlet-2, and MIDlet-3. The name identifies the MIDlet to the user; the icon is the path to an image (in the portable PNG format) in the JAR file; and the class must extend the MIDlet class and have a public constructor with no arguments. Required.
MIDlet-Data-Size
The minimum number of bytes of persistent storage that the MIDlet requires in order to run. Optional. If not specified, the default is zero.
MIDlet-Description
A description of the MIDlet suite. Optional.
MIDlet-Icon
The path of a portable graphics format (PNG) file within the JAR file, used by the application management software to identify the MIDlet suite. Optional.
MIDlet-Info-URL
An URL describing the MIDlet suite in greater detail. Optional.
MIDlet-Name
The name of the MIDlet suite. Required.
MIDlet-Vendor
The vendor of the MIDlet suite. Required.
MIDlet-Version
The version number of the MIDlet suite. Must be in the format XX.YY or XX.YY.ZZ, where XX is the major revision number, YY is the minor revision, and ZZ is the optional micro revision number. If the micro revision number is omitted, it defaults to zero. Required.
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 113
Profiles
113
Application Descriptors The only problem with using a manifest to describe the MIDlets in the suite is that the manifest must be extracted from the JAR file. In other words, this process involves downloading the JAR file to the device, which is a potentially expensive (and lengthy) proposition if you are performing this task via a public wireless data network. Imagine downloading a MIDlet suite only to discover that it requires a higher version of the MIDP and will not even install on your device. To avoid these problems, the MIDP specification defines an optional application descriptor. An application descriptor is a text file that is similar to a manifest, except that it is not packaged in the JAR file. Like the manifest, it consists of a series of attributes that describe a MIDlet suite. The possible attributes are listed in Table 6.2—some of which are shared with the manifest. Of the shared attributes, the MIDlet-Name, MIDlet-Version, andMIDlet-Vendor attributes must have identical values in both the manifest and the application descriptor. If any other shared attributes are different, the ones in the descriptor override those in the manifest. Here is a sample manifest for the same set of arcade games: MIDlet-Name: ClassicGames MIDlet-Version: 1.0.0 MIDlet-Vendor: Old Arcade Games, Inc. MIDlet-Description: A set of arcade classics for your MID. MIDlet-Info-URL: http://www.oagames.com/classicgames MIDlet-Data-Size: 200 MIDlet-Jar-Size: 14398 MIDlet-Jar-URL: http://www.oagames.com/classicgames/oacg.jar
The use of an application descriptor is optional but recommended, because it enables the device to verify various things. Among these functions is verifying whether a newer version of the MIDlet suite is already installed on the device, whether the JAR file is too big for the device, whether it requires too much memory when running, and so on. The device can verify these features without actually having to download the JAR file itself. This function saves both time and money for the user of the device.
67957_Wiley_Giguere_CH06x
114
10/17/2000 4:51 PM
Page 114
CHAPTER 6
Table 6.2 MIDlet Application Descriptor Attributes NAME
DESCRIPTION
MIDlet-Data-Size
The minimum number of bytes of persistent storage that the MIDlet requires to run. Optional. If not specified, the default is zero.
MIDlet-Description
A description of the MIDlet suite. Optional.
MIDlet-Info-URL
An URL that describes the MIDlet suite in greater detail. Optional.
MIDlet-Jar-Size
The size of the MIDlet suite in bytes. Required.
MIDlet-Jar-URL
The URL from which to download the MIDlet suite. Required.
MIDlet-Name
The name of the MIDlet suite. Required.
MIDlet-Vendor
The vendor of the MIDlet suite. Required.
MIDlet-Version
The version number of the MIDlet suite. Must be in the format XX.YY or XX.YY.ZZ, where XX is the major revision number, YY is the minor revision, and ZZ is the optional micro revision number. If the micro revision number is omitted, it defaults to zero. Required.
The MIDlet specification defines a new Multipurpose Internet Mail Extensions (MIME) type for the descriptor, text/vnd.sun.j2me. app-descriptor, as well as a default file extension, jad. This format allows the descriptors to be fetched from a Web server by using HTTP, although the use of that protocol is not a requirement. Application Lifecycle Once an application is installed on a device, it stays there until specifically uninstalled by the user of the device. Installation is a permanent action. The application management software that comes with the device activates the application. The MIDP specification does not define how this software works, but it does define how the software creates and activates a MIDlet. The application manager first creates an instance of the MIDlet by using its no-argument constructor. It then calls the MIDlet’s startApp method to place it in the active state.
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 115
Profiles
115
A MIDlet can be in one of three possible states: active, paused, or destroyed. If the MIDlet is active, it is currently running. If the MIDlet is paused, it has released any resources that it was holding on to (such as a network connection) but is ready to be reactivated. A MIDlet in the destroyed state has permanently shut itself down, released all its resources for good, and is waiting to be garbage collected. State changes occur in response to the user interacting with the application management software. When the MIDlet is activated, its startApp method is called. When it is paused, the pauseApp method is called. When it is destroyed, the destroyApp method is called. If the MIDlet is not ready to be started or destroyed, it can throw a MIDletStateChangeException to defer the state change. The MIDlet can also enter the paused or destroyed states at any time by invoking the notifyPaused or notifyDestroyed methods.
User Interface Classes The most exciting part of the MIDP specification to many programmers are the user interface (UI) classes that it defines. These classes are informally referred to as the MIDP UI APIs and are part of the javax. microedition.lcdui package. All classes referred to in this section are from this package unless otherwise noted. The MIDP UI APIs and Abstract Windowing Toolkit (AWT) The MIDP UI APIs are not based on the AWT. Although AWT forms the basis for the user interface classes defined by J2SE, the MIDP expert group felt that it was not suitable for use on MIDs because the user interaction model on these devices is different. AWT is also quite memoryintensive. It creates many objects (the classes java.awt.Event, java.awt.Point, and java.awt.Dimension are used extensively, for example) that can easily overwhelm the garbage collector on a small device. AWT also requires the existence of a pointing mechanism, something not found on all devices targeted by the MIDP specification. The KVM team used similar reasons for rejecting AWT, but they also had the freedom to build Palm-specific UI classes. Therefore, the classes found in the Palm implementation of the CLDC are not the
67957_Wiley_Giguere_CH06x
116
10/17/2000 4:51 PM
Page 116
CHAPTER 6
same as those defined by the MIDP. (Remember that the CLDC does not define any UI classes, so the reference implementation had to include some way in which to interact with the user until a formal set of classes could be defined. We will discuss these in the next two chapters.) Like AWT, however, the MIDP UI APIs are meant to be cross-platform (at least, to a certain degree). The MIDP UI APIs are composed of two sets of classes: a high-level API and a low-level API. With the high-level API, an application uses task-oriented abstractions to define what the user interface should do (such as present a list of choices to the user) but not specifically how to perform the actions. An application that uses the high-level API exclusively is guaranteed to be portable across MIDP-enabled devices. The low-level API, on the other hand, provides direct access to the display and to any input events. But because different devices have different sizes of displays and different input methods, dependence on these low-level capabilities can limit application portability. When it comes right down to it, the high-level API is really geared toward business-application developers, while the low-level API is meant for game developers. The MIDP implementation can, of course, also add its own devicespecific user interface classes to expose features that are unique to the device. Using these classes will limit application portability, just like the low-level UI API does. Screens and Events A MIDlet uses screens for output purposes. A screen is an object that draws graphics on the device’s display, which is analogous to a window in most user interface systems. Its behavior, however, is different from most windowing systems: only one screen at a time is visible. In J2SE terms, perhaps the best analogy is to think of screens as individual cards in a card layout as defined by java.awt.CardLayout. In this model, an application is basically a deck that switches from card to card in response to user input or other input. There are three kinds of screens from which to choose. The simplest to use are the predefined screens that encapsulate common user interface behaviors. For example, there is a List screen that displays a list of choices to the user. How that list is displayed—by using a listbox, a
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 117
Profiles
117
Table 6.3 Predefined Screens CLASS
DESCRIPTION
Alert
Displays text and images to the user for a specific length of time or until the user dismisses the screen. Limited control over the layout.
List
Displays a list of choices. Each choice is a string and an optional image. How the list is displayed is up to the screen, but the user can navigate through the list of choices as long as necessary. Both single and multiple selection are supported.
TextBox
Displays a screen of titled, editable text with an optional initial value and a maximum number of characters to accept. Simple constraints are defined for entering common values such as URLs, e-mail addresses, phone numbers, numbers, and passwords.
drop-down listbox, a menu, or something else—is up to the implementation. The application is merely notified when the user chooses an item. All predefined screens are subclasses of the abstract class Screen and are summarized in Table 6.3. If the predefined screens are not suitable, individual user interface controls can be grouped together on a screen called a form, although the exact layout of the controls is left up to the screen. A form is defined by the Form class, which is also a subclass of Screen. The items that can be placed on a form are listed in Table 6.4. For complete control over what is drawn on the screen, a canvas screen is used. Using a canvas, which is a subclass of the Canvas class, is an all-or-nothing proposition. You have to do all of the drawing. The Canvas class is the only screen class that does not extend Screen. All screens, however, are subclasses of Displayable. The application uses the Display class to control which screen is current and to obtain some minimal information about the display. Display is a singleton class, which means that there is only one instance of a Display object created per MIDlet. The MIDlet calls Display.getDisplay in order to obtain the object. Input events are also handled by using different abstraction levels. At the highest level, events are handled by defining commands, which are objects that define actions with semantics drawn from a predefined list. For example, the application would display the previous screen in
67957_Wiley_Giguere_CH06x
118
10/17/2000 4:51 PM
Page 118
CHAPTER 6
Table 6.4 Form Items CLASS
DESCRIPTION
ChoiceGroup
Displays a list of choices. Each choice is a string and an optional image. Both single and multiple selection are supported. Single selection is most often represented by radio buttons, and multiple selection is represented by check boxes. But the implementation must decide on the best approach.
DateField
Displays editable date and/or time information
Gauge
Displays a bar graph. Typically used to display progress bars or to let the user choose between a fixed range of values.
ImageItem
Displays a labeled image. The image can specify limited layout information in order to control its placement on the screen.
StringItem
Displays labeled, non-editable text.
TextField
Displays labeled, editable text with an optional initial value and a maximum number of characters to accept. Simple constraints are defined for entering common values such as URLs, e-mail addresses, phone numbers, numbers, and passwords.
response to a back command. How the user invokes the command is out of the application’s control. The device is free to use buttons, menus, or whatever other controls that it wants—regardless of whether they are hardware- or software-based. All the application can do is specify the type and priority of the command and assign it a label. Commands are instances of the Command class. Commands can be attached to any screens (any subclass of Displayable). Lower-level events such as key presses are only available on canvases. The system calls methods on the Canvas class in response to individual events in a way that is reminiscent of the original AWT event model. Instead of using event objects, however, the event parameters—the keycode for key events and the x and y coordinates for pointer events—are passed as simple integers. Keycodes are defined for the basic keys that are common to all MIDs (specifically, the keys on a telephone keypad), but any other keys are device-specific and nonportable. A mapping from keycodes to abstract game events (such as DOWN or FIRE) is also available. The mapping is controlled by the device and can work with keypads or full-function keyboards. As for pointer events, not every device supports pointer-based input, so an application should not depend on their existence; rather, it should check for the capability when started and adapt itself accordingly.
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 119
Profiles
119
Drawing and Repainting The low-level API defines methods for drawing text and graphics on the display and for repainting the display. These capabilities are only available with canvases, because painting is handled automatically for all other screen types. Drawing is done by using a conventional two-dimensional model with the origin of the coordinate system in the upper-left corner. Twenty-fourbit color is supported, although the device might map the colors onto its own less-extensive palette as appropriate. Three font faces are available in three sizes and four styles, although the device might not support them all and will substitute a different font if necessary. The expected methods are available for drawing strings, rectangles, lines, images, and arcs. Drawing can be done directly to the display or to an off-screen memory buffer. These capabilities are all available through the Graphics class. Repainting occurs when the system calls the canvas’ paint method, which must be overridden by subclasses of Canvas. A Graphics object is passed to the paint method with its clipping area set to the union of the areas that need repainting. Here is a simple example of a paint method: protected void paint( Graphics g ){ g.setGrayScale( 255 ); g.fillRect( 0, 0, getWidth(), getHeight() ); g.setGrayScale( 0 ); g.drawLine( 0, 0, getWidth(), getHeight() ); }
Double Buffering In order to perform flicker-free animation, the double buffering drawing technique is often used. In double buffering, you draw not to the display but to a memory buffer, drawing a complete image every time. When you are done drawing to the buffer, you use a single operation to copy the contents of the buffer to the display. Usually, this process is much faster than using individual drawing operations directly on the display and avoids any noticeable flicker. Although the MIDP supports this kind of animation, you might find that the device does not perform the copy quickly enough to avoid the user noticing it. If this situation is the case, your best choice is to draw the individual changes instead of redrawing the entire image. This process is harder with the MIDP, however, because the Graphics class does not even support any methods to perform exclusive OR (XOR) or other bit operations.
67957_Wiley_Giguere_CH06x
120
10/17/2000 4:51 PM
Page 120
CHAPTER 6
Like any modern graphics system, multiple paint requests are coalesced by the system into a single paint request whenever possible, because there is usually a slight delay between a paint request and the time that the painting actually occurs. You can call the serviceRepaints method to force the painting to occur right away. Threading Issues Like the original AWT classes (but unlike the newer Swing classes), the MIDP UI APIs are thread-safe. The methods can be called at any time from any thread. The only potential for deadlock occurs when you use serviceRepaints to force immediate repainting of the display. To avoid the deadlock, do not lock any objects that the paint method will use. To run some code after any pending repaints have been serviced, use the callSerially method of the Display class, passing in a Runnable object. The object’s run method will be invoked soon after the initial call. The run method is always called on the event thread, no matter which thread invoked callSerially.
Other MIDP Classes Apart from the MIDlet and UI classes, the MIDP specification also defines classes for data persistence, networking, and task scheduling. The Record Management System The MIDP defines a set of classes in the javax.microedition.rms package for storing data in a simple database. The classes are referred to as the Record Management System (RMS) because they work on arbitrary records of data, which are read and written by using byte arrays. Remember, there is no object serialization in the CLDC. If you are at all familiar with a conventional record-based database system, such as the Palm OS native database format, you will not find anything surprising here. Records are stored in a record store by the RMS and are represented by the RecordStore class. The contents of a record store persist across different invocations of the MIDlet that created it. The record store can
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 121
Profiles
121
be accessed by other MIDlets, but only if they are members of the same MIDlet suite. The record store is removed whenever the MIDlet suite with which it is associated is removed. No APIs are defined by the RMS or elsewhere in the MIDP to interface with any native databases that the device might support. Any such APIs are left for the implementation to provide as non-portable extensions to the profile. The RMS implementation might actually use a native database to store the records, but the details are never exposed to the developer. A record store has a name that must be unique within the MIDlet suite (different stores in different suites can use the same name) and that can consist of no more than 32 characters. Methods are available for creating, opening, closing, and deleting record stores, as well as listing all of the available record stores. Here is a simple example that uses a few of these methods: import javax.microedition.rms.*; // Cycle through existing record stores try{ String[] stores = RecordStore.listRecordStores(); for( int i = 0; stores != null && i < stores.length; ++i ){ RecordStore s = RecordStore.openRecordStore( stores[i], false ); System.out.println( "Record store " + stores[i] + " has " + s.getNumRecords() + " records." ); s.closeRecordStore(); } } catch( RecordStoreNotFoundException e ){ ..... } catch( RecordStoreFullException e ){ ..... } catch( RecordStoreException e ){ ..... }
Each record in a store is given a unique identifier, the record ID, which is an integer greater than or equal to 1. All operations on an individual record take a record ID as a parameter. The RMS provides the usual operations for creating, reading, writing, and deleting records. Record change notifications are passed to any registered RecordListener objects that are associated with the record store. All operations on
67957_Wiley_Giguere_CH06x
122
10/17/2000 4:51 PM
Page 122
CHAPTER 6
individual records are performed by using byte arrays. The DataInputStream, DataOutputStream, ByteArrayInputStream, and ByteArrayOutputStream classes from the javax.microedition.io package (part of the CLDC) can be used to move data in and out of byte arrays if you would rather not deal with byte values directly: import javax.microedition.rms.*; import java.io.*; // Note that exception handlers are left out for simplicity. RecordStore r = .....; // Get data out of the first record using a datainput stream. byte[] data = r.getRecord( 1 ); DataInputStream in = new DataInputStream( new ByteArrayInputStream( data ) ); boolean bval = in.readBoolean(); String sval = in.readUTF(); // etc. etc. // Store data into the first record using a dataoutput stream. ByteArrayOutputStream bstream = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream( bstream ); out.writeBoolean( true ); out.writeUTF( "some string" ); data = bstream.toByteArray(); r.setRecord( 1, data, 0, data.length );
Sorting and searching is done by using the enumerateRecords method, which returns a RecordEnumeration object for traversing through a list of records. You can pass in optional RecordComparator and RecordFilter objects to determine the order and subset of the records that are to be returned. The enumeration can even register its own RecordListener to track any changes that you make to a record store in order to maintain a valid record list (this operation is expensive, however, if you are constantly making changes). Note that the actual record store is never sorted, so two different RecordEnumeration objects can return two different sorts of the same record store without conflict.
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 123
Profiles
123
The RMS classes are thread-safe in the sense that individual operations are guaranteed to be atomic. If two threads call setRecord on the same record, no corruption will occur. But the final contents of the record will be set by the second thread to run. The application must ensure that different threads do not write over each other’s data. HTTP Connections The MIDP specification adds a communication driver for the HTTP protocol to the Generic Connection framework. HTTP is a client-server protocol in which the client makes requests and the server sends back responses. A subset of the HTTP 1.1 protocol is supported—the GET, POST, and HEAD methods—with full header support in both requests and responses. Connections are made by using a Universal Resource Identifier (URI) that starts with the http: prefix, as shown in our discussion of the Generic Connection framework. What is returned is an instance of an HttpConnection—an interface that extends ContentConnection. Note that while HTTP usually runs over a circuit-oriented (TCP/IPbased) network, HTTP does not require such a network. The device is free to simulate such a connection as appropriate for the network that it is using. This situation usually means installing some kind of gateway to act as the bridge from the network to the Internet. The implementation must be completely transparent to a program that is making use of HTTP connections, no matter how it is done. Here is a simple example of using the HTTPConnection class to access a Web page—again, with exception handling removed for simplicity: import javax.microedition.io.*; import java.io.*; HttpConnection conn = (HttpConnection) Connector.open( "http://www.ericgiguere.com" ); InputStream in = conn.openInputStream(); String cache = conn.getHeaderField( "Cache-control" ); int length = conn.getLength(); if( length != -1 ){
67957_Wiley_Giguere_CH06x
124
10/17/2000 4:51 PM
Page 124
CHAPTER 6 // // } else // // }
length is known, could read directly into a byte array if convenient { length is not known, have to read data a byte at a time until the end-of-stream is reached
The only other restriction that the MIDP specification makes is that if the device includes a User-Agent header in its requests, it must contain information about the CLDC and MIDP versions being used. Additionally, the Content-Language header must be supplied in order to identify the locale of the device. You perform this task by calling the setRequestProperty method before opening an input or output stream on the connection: HttpConnection conn = (HttpConnection) Connector.open( "http://www.ericgiguere.com" ); conn.setRequestProperty( "User-Agent", "Profile/MIDP-1.0 Configuration/CLDC-1.0" ); conn.setRequestProperty( "Content-Language", "en-US" ); InputStream in = conn.openInputStream();
A Web server can use the information in these headers in order to prepare its response based on the device’s capabilities and locale. No other protocol is specified as part of the profile, although of course, implementations can provide their own device-specific communication drivers. RIM’s MIDP implementation, for example, provides a driver for directly sending and receiving packets on the wireless network. Timer Notifications The final set of classes defined by the MIDP specification are the two timer classes: java.util.Timer and java.util.TimerTask. These classes are inherited from J2SE 1.3 and are used to schedule tasks for later execution or to notify the application when a timer expires. A Timer object creates a background thread on which it will execute callbacks to objects that implement the TimerTask interface. These callbacks can occur at specific times or at regular intervals. Here is a simple example: class DoSomething extends TimerTask { public void run() {
67957_Wiley_Giguere_CH06x
10/17/2000 4:51 PM
Page 125
Profiles
125
// do something here } } .... // Schedule a task to occur in 10 seconds Timer t = new Timer(); t.schedule( new DoSomething(), 10000 );
Other Profiles At this writing, a number of other J2ME profiles are under development.
The PDA Profile Like the MIDP, the PDA Profile is built on top of the CLDC, but is targeted specifically at personal digital assistants, which have more memory and more sophisticated user interfaces than the low-end devices targeted by the MIDP. The PDA Profile requires that a device have at least 512K of memory (either RAM or a combination of ROM and RAM) available for the Java runtime environment. The profile also requires the device to have a display with a resolution of at least 20,000 pixels, some kind of pointing device, and the ability to enter character data. Although the PDA Profile is still in a very early stage of development at this writing, all indications are that it will include a set of user interface classes that will subset the AWT classes of J2SE. The PDA Profile expert group includes the developers of kAWT, a subset of AWT written for the Palm port of the CLDC reference implementation. To provide compatibility with the MIDP, the PDA Profile may also include the MIDP user interface components, written to use the AWT subset.
The Foundation Profile The Foundation Profile is built on top of the CDC, not the CLDC, and is meant to serve as the foundation for other CDC-based profiles. It bumps up the minimum memory requirements of the CDC to 1024K of non-volatile memory and 512K of volatile memory. It does not provide
67957_Wiley_Giguere_CH06x
126
10/17/2000 4:51 PM
Page 126
CHAPTER 6
any user interface classes; rather, these are provided by a profile based on the Foundation Profile. What the Foundation Profile does is augment the CDC with many of the J2SE APIs that it omits. The complete list is too long to print here, so refer to the specification for all of the details.
The Personal Profile The Personal Profile is the first J2ME-based version of the PersonalJava runtime environment. Rather than existing separately from J2ME, the new Personal Profile builds on top of the Foundation Profile by adding the classes that are necessary for running PersonalJava applications on a CDC-based device. The minimum memory requirements are significantly higher than the Foundation Profile—2.5MB of non-volatile memory and 1MB of volatile memory. Perhaps the biggest addition that the Personal Profile brings to the Foundation Profile is that the Personal Profile includes the user interface classes from PersonalJava.
The RMI Profile The final profile being developed is the RMI Profile. Like the Personal Profile, the RMI Profile is built on top of the Foundation Profile and has the same minimum memory requirements as the Personal Profile. It just adds the J2SE RMI classes to the Foundation Profile. Applications that are built by using the RMI Profile will be compatible and interoperable with RMI-based applications that are built with J2SE 1.2 or higher.
Chapter Summary In this chapter, we described the MIDP in quite some detail and briefly mentioned other profiles that are under development. The MIDP is particularly important because it is the first profile that defines user interface APIs for small devices. In the next part of this book, we will look at implementations that put these specifications into practice.
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 127
PA R T
THREE
Java 2 Micro Edition (J2ME) Implementations
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 128
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 129
CHAPTER
7
The Connected Limited Device Configuration (CLDC) Reference Implementation
A
t this point, you are probably wondering when we will get down to the nitty-gritty details of Java 2 Micro Edition (J2ME) coding. This chapter and the remaining chapters are the ones for which you have been waiting. This chapter shows you how to run CLDC-based Java programs on your desktop computer, running either the Windows or Solaris operating systems, by using the Connected Limited Device Configuration (CLDC) reference implementation.
Overview All of the information in this chapter is based on the CLDC 1.0 reference implementation, which you can find at www.sun.com/software/ communitysource/j2me/. This implementation is free to download and use but is subject to the restrictions of the Sun Community Source License (SCSL).
129
67957_Wiley_Giguere_CH07x
130
10/17/2000 4:52 PM
Page 130
CHAPTER 7
About SCSL The Sun Community Source License allows you to download the source to specific Sun-developed software for your own research and development purposes. If you write a product that requires or is based on the Sun software, you must obtain a deployment license from Sun Microsystems. Refer to the licensing page at www.sun.com/software/communitysource/index.html for more details.
There are two forms of the reference implementation: the official reference platform, which runs on Windows or Solaris, and a port of the reference for Palm devices. We will discuss the Palm port in the next chapter, so in this chapter we will only deal with the reference implementation. Keep in mind that what we are discussing here is an implementation of the CLDC—not the Mobile Information Device Profile (MIDP), which we will discuss later in Chapter 9, “The MIDP Early Access Release.” The CLDC reference implementation, however, does include a number of additional classes that are comparable to what you will find in the MIDP, except that these classes are not as general—and Sun Microsystems does not officially support them. For brevity, we will often refer to the CLDC 1.0 reference implementation as “the CLDC” throughout the remainder of this chapter.
Installation The CLDC is packaged as a single ZIP archive for both Windows and Solaris. Installation is simple. Just extract the contents of the ZIP file into a directory on your desktop system. You do not need to invoke a setup program. The ZIP file contains the following items: ■■
■■
Binaries for the KVM interpreter and the preverification tool (in the bin directory) as well as the complete source for both (in the kvm and tools\preverifier directories) Compiled versions of the CLDC classes and the non-CLDC extensions (in the bin\api directory)
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 131
The Connected Limited Device Configuration (C LD C) Reference Implementation ■■
■■ ■■
■■
131
Documentation for all of the classes, in Hypertext Markup Language (HTML) and Portable Document Format (PDF), along with release notes, the complete CLDC 1.0 specification, and a guide to porting the KVM (in the docs directory) Sample programs (in the samples and bin\samples directories) Source code for the Java Application Manager (JAM), a sample implementation of the application management software referred to by the CLDC specification (in the jam directory) Source code for the JavaCodeCompact (JCC) tool, which is used for pre-loading/pre-linking Java classes for use by the KVM (in the tools\jcc directory). We do not discuss JCC here, because it is primarily a tool for device manufacturers.
The source code for the KVM and the tools might not interest you, but the reference implementation is for device manufacturers (or anyone else who wants to port the KVM to a different platform) as well as third-party developers. This implementation includes everything that is necessary to build the complete reference implementation on either Windows or Solaris platforms. Refer to the release notes and the KVM Porting Guide for details concerning how to compile the KVM and all of the tools. Note that some parts of the KVM are optional and can be enabled or disabled when the virtual machine (VM) is built. In the bin directory, you will find two binaries for the KVM for each platform: a regular KVM (kvm.exe for Windows and kvm for Solaris) and a KVM with JAM support (kvm_j.exe for Windows and kvm_j for Solaris). If you want to experiment with different combinations of optional features, you will have to compile your own version of the KVM.
Running the Samples The CLDC comes with a number of sample programs to get you started. If you have built the KVM yourself, there is a batch file for Windows (kw.bat) or a shell file for Unix (ku) in the samples directory that you can use to run an individual sample. To run the samples by using the pre-built KVM binary, just change these files. For example, the Windows batch files looks like the following:
67957_Wiley_Giguere_CH07x
132
10/17/2000 4:52 PM
Page 132
CHAPTER 7 ..\kvm\VmWin\build\kvm.exe -classpath ..\api\classes;..\samples\classes %1%
Just change the path to the kvm.exe and to the classes: ..\bin\kvm.exe -classpath ..\bin\api\classes;..\bin\samples\classes %1%
Alternatively, you can define a KVM_HOME environment variable and set it to the root of the CLDC installation and change the batch file to the following: %KVM_HOME%\bin\kvm.exe -classpath %KVM_HOME%\bin\api\classes;%KVM_HOME%\bin\samples\classes %1%
Place the batch file somewhere in your command path, and you will be able to run the samples from any directory. Otherwise, you have to run them from within the samples directory. You can define a similar shell script for Unix or just define a shell alias. Now, you are ready to run the samples. The samples are mostly simple games that are meant to demonstrate the user interface classes and the speed of the KVM more than doing anything particularly useful. This statement brings up an interesting point. What kind of user interface does the reference implementation provide? The answer is that the reference implementation provides additional non-CLDC classes that simulate the user interface of a Palm device. In other words, they have ported the classes from the Palm CLDC implementation, which we will discuss in the next chapter, and made them work with Windows and Unix. You should note that these classes—all of which are found in the com.sun.kjava package—are not an official part of the CLDC specification. These and other classes that are not in the java or javax packages are provided solely for testing and demonstration purposes. Remember that configurations are not expected to be used by themselves; instead, applications are meant to run in the context of a profile that provides additional functionality that is not found in the configuration. Run the first sample, UITest, from the samples directory by typing either kw UITest for Windows or ku UITest for Unix. You should immediately see a window displaying a crude Palm-like device, as shown in Figure 7.1. This device is the Palm simulation provided by the CLDC, which is not sophisticated but adequate for testing purposes.
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 133
The Connected Limited Device Configuration (C LD C) Reference Implementation
133
Figure 7.1 The KVM Palm-like user interface for Windows.
The display is 160 pixels wide by 160 pixels high, just like the Palm display. Pen taps are simulated by moving the mouse over the display and pressing the primary mouse button (usually the left button). Pen strokes are simulated by dragging the mouse across the display. The elliptical areas at the bottom of the display represent the buttons on a Palm device. The leftmost area is the power button, followed by the Date Book and Address Book buttons, the scroll up and scroll down buttons, and the To Do and Memo Pad buttons. You can press the power button at any time to exit the simulation, but be aware that on a real Palm device, that action will not terminate a running application, it will just suspend the device. Character input on a real Palm device is done by using pen strokes, but with the simulator, just use the keyboard. The samples are summarized in Table 7.1. Refer to the release notes for detailed descriptions and instructions. Each sample is run by using the kw or ku command and the name of the sample as its only argument. The most interesting and complicated samples are dots.DotGame and missiles.Missiles, the latter being much easier to play on an actual device. You can find the source for each sample in the samples directory.
67957_Wiley_Giguere_CH07x
134
10/17/2000 4:52 PM
Page 134
CHAPTER 7
Table 7.1
CLDC Samples
NAME
DESCRIPTION
dots.DotGame
A game where players take turns connecting dots to outline boxes. You can play against the computer or against another human on another device.
Dragon
Draws dragon-like fractal images wherever you tap on the display.
ManyBalls
Uses threads to animate several bouncing balls.
missiles.Missiles
A game where you try to shoot flying saucers out of the sky while avoiding the missiles as they drop.
Pong
The classic ball-and-paddle game.
Scribble
Lets you scribble on the display while animating a bouncing ball.
StarCruiser
A game where you move your spaceship to avoid oncoming asteroids.
ThreeDLogo
Draws a logo that you can rotate in three dimensions. When you run this game on the Palm, you can even beam the rotation information to another device that is running the same application.
UITest
Demonstrates a few user interface controls.
Compiling, Preparing, and Running Classes After playing with the samples, you should try writing an application of your own. You can perform this task on the desktop computer by using your normal development tools. You will need the compiler and tools from JDK 1.2.2 or higher in order to compile the files, after which you will run them through the preverification tool in order to prepare them for execution by the KVM. The basic command to compile a set of classes is as follows under Windows: javac -g:none -bootclasspath %KVM_HOME%\bin\api\classes -classpath %KVM_CLASSPATH% -d %KVM_TMP_DIR% *.java
This command, and all the commands in this section, should be entered as a single line on the console. The Unix command is identical, except that the paths and environment variables are in shell format instead of MS-DOS format. In either case, it is a fairly standard javac command line, except for the addition of the –g and –bootclasspath options.
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 135
The Connected Limited Device Configuration (C LD C) Reference Implementation
135
The –g option ensures that javac does not generate any debugging information into the class files that it outputs. Also, because javac automatically adds the Java 2 Standard Edition (J2SE) runtime classes to the classpath (a feature that was new to JDK 1.2), the –bootclasspath option overrides this behavior by adding the CLDC classes instead. You must not include the J2SE classes in the classpath in order to ensure that you do not accidentally use classes that are not in the CLDC. Notice that the command references the KVM_HOME, KVM_CLASSPATH, and KVM_TMP_DIR environment variables. Define KVM_HOME as we did for running the samples. KVM_CLASSPATH is the set of directories and/or Java Archive (JAR) files to use when searching for classes that are not explicitly passed to javac for compilation. You can, of course, use the normal CLASSPATH variable instead, but it is often simpler to separate the Java 2 Micro Edition (J2ME) classpath from the J2SE classpath. KVM_TMP_DIR is the temporary output directory where the class files reside before being preverified. The next step is to run the preverifier on the class files: %KVM_HOME%\bin\preverify -d %KVM_OUTPUT_DIR% -classpath %KVM_CLASSPATH%;%KVM_HOME%\bin\api\classes %KVM_TMP_DIR%
The preverifier can work on individual class files or directories of class files. Directories are searched recursively for any class files. Here, we have defined another environment variable, KVM_OUTPUT_DIR, to hold the preverified class files. Note that if the output directory is in the preverifier’s classpath (in other words, if KVM_OUTPUT_DIR is in KVM_CLASSPATH), the preverifier will not work correctly. At this point, you can either run the classes directly or package them into a JAR file. The command to use in order to run them is as follows: %KVM_HOME%\bin\kvm -classpath %KVM_OUTPUT_DIR%;%KVM_CLASSPATH%;%KVM_HOME%\bin\api\classes MainClass
This example assumes, of course, that the class to run is called MainClass. Note that if you do not specify the –classpath option, the KVM uses the value of your CLASSPATH environment variable.
67957_Wiley_Giguere_CH07x
136
10/17/2000 4:52 PM
Page 136
CHAPTER 7
To actually start the application, the KVM loads the specified class and looks for the usual application entry point: public static void main( String[] args ) { // ... do the application stuff }
The application runs until all threads terminate (the CLDC does not enable daemon threads to be created, and all threads have equal standing) or until the System.exit method is called. As you experiment with the KVM, you will find it convenient to define a set of batch files or shell scripts in order to perform these operations and to reduce the amount of typing that you do. In formal projects, you will probably use a makefile of some kind—just like the sample makefiles that come with the CLDC.
The Hello World Application Let’s compile and run a simple application. Define the HelloWorld class as follows: public class HelloWorld { public static void main( String[] args ) { System.out.println( "Hello, world!" ); // Wait for ten seconds try { Thread.sleep( 10000 ); } catch( InterruptedException e ){ } } }
All this class does is print a line of text and wait 10 seconds before exiting. Now, compile, preverify, and run the class. On Windows, the sequence of three commands would be as follows: javac -g:none -bootclasspath %KVM_HOME%\bin\api\classes -classpath %KVM_CLASSPATH% -d %KVM_TMP_DIR% HelloWorld.java
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 137
The Connected Limited Device Configuration (C LD C) Reference Implementation
137
%KVM_HOME%\bin\preverify -d %KVM_OUTPUT_DIR% -classpath %KVM_CLASSPATH%;%KVM_HOME%\bin\api\classes %KVM_TMP_DIR% %KVM_HOME%\bin\kvm -classpath %KVM_CLASSPATH%;%KVM_HOME%\bin\api\classes HelloWorld
You should see the string Hello, world! printed on your console. Are you surprised that the program worked? If you read through the CLDC API specification, you saw that the System.out and System. err output streams were both available. In the reference implementation, these streams are both redirected to the KVM’s own standard output stream and from there to the console. Not all devices support a console, of course, and on those devices, the streams might write to a file, to a database, or to some other device-specific output mechanism. The Palm implementation, for example, writes its output to a record database. In general, then, you should only use System.out for debugging and tracing purposes, because the output might not be visible to the program user.
The Hello World Spotlet To display a user interface and to receive input events, an application must define a class that extends the com.sun.kjava.Spotlet class (the user interface classes were originally created for the Spotless project that we discussed in Chapter 4). Such an application is called a spotlet. We will defer our discussion of spotlets until the next chapter, but here is the HelloWorld application reworked as a spotlet: import com.sun.kjava.*; public class HelloWorldUI extends Spotlet { public static void main( String[] args ) { new HelloWorldUI(); } public HelloWorldUI() { Graphics g = Graphics.getGraphics(); g.clearScreen();
67957_Wiley_Giguere_CH07x
138
10/17/2000 4:52 PM
Page 138
CHAPTER 7 g.drawString( "Hello, world!", 0, 0 ); } }
Compile and preverify this class as we did with HelloWorld, replacing all references to HelloWorld with HelloWorldUI. Run the spotlet, and you will see the output shown in Figure 7.2. Press the simulator’s power button to exit the application.
Spotlets Keep Running Note that when a spotlet is created, the KVM keeps running until the user presses the simulator’s power button or until the spotlet invokes System.exit. A static initializer in the Spotlet class creates a thread that waits for and services input events.
Figure 7.2 The HelloWorldUI spotlet.
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 139
The Connected Limited Device Configuration (C LD C) Reference Implementation
139
Memory Usage When the KVM starts, it immediately allocates all of the memory that it will require to run an application—except for any memory that is separately allocated by native methods. A desktop system running Windows or Unix has much more memory than a typical device targeted by the CLDC. To more properly emulate these devices, the desktop version of the KVM limits the amount of memory that it can allocate for the Java heap to 150,000 bytes. You can change this limit only by recompiling the VM.
The JAM The CLDC reference implementation includes a sample implementation of a JAM. The CLDC specification does not state how the application management software is to be implemented (it does not actually refer to it by a specific name), other than acknowledging its existence. There has to be some way to download and install Java applications and make some general statements about what the applications should do. CLDC-based profiles can be more specific, of course, and the MIDP does just that by requiring specific attributes in a JAR manifest and defining an optional application descriptor. The JAM that accompanies the CLDC reference implementation is just a sample that device manufacturers and other CLDC implementers can use as a basis for their own application management software. In particular, it does not follow the MIDP specification’s manifest and descriptor requirements, although its requirements are similar. To use the JAM, you need three items: a properly-marked JAR file, a descriptor file, and a JAM-enabled version of the KVM. The latter is included with the CLDC reference implementation, and you will find a kvm_j executable in the bin directory. This executable is identical to the KVM executable that you have used so far, except that it supports three new command-line options: ■■ ■■
The –jam option enables JAM. The –repeat option makes the JAM repeat failed downloads until a download succeeds.
67957_Wiley_Giguere_CH07x
140
10/17/2000 4:52 PM
Page 140
CHAPTER 7 ■■
The –appsdir path option specifies the path to the JAM application installation directory. If not specified, it defaults to the instapps subdirectory of the current directory.
You must set the classpath to include the CLDC runtime classes but not the application classes. Also, instead of specifying the name of the main class, you pass the URL of the JAM descriptor, which is a text-file ending (.jam) fetched from either a Web server or from the local file system. For example: kvm -jam -repeat -appsdir http://localhost/MyApp.jam
The JAM descriptor describes the application to be downloaded, installed, and run. This descriptor is really just a JAR manifest with the attributes defined in Table 7.2. For example: Application-Name: MyApp Application-Version: 1.0.0 KVM-Version: 1.0 JAR-File-URL: MyApp.jar JAR-File-Size: 8223 Main-Class: com.mycompany.MyApp Use-Once: no
After fetching the descriptor, the KVM uses these attributes to determine whether a version of the application is already installed locally. If so, and if the version is equal to or greater than the version specified in the descriptor file, then the already-installed JAR file is used to launch the application. Otherwise, a new JAR file is downloaded and run in its place. Table 7.2
JAM Attributes
NAME
DESCRIPTION
Application-Name
The name of the application
Application-Version
The version of the application (a string of the form XX.YY or XX.YY.ZZ, where XX is the major version, YY is the minor version, and ZZ is the micro version)
KVM-Version
The version of the KVM required to run the application
JAR-File-URL
The URL to use to download the application
JAR-File-Size
The size of the application in bytes
Main-Class
The name of the application’s main class
Use-Once
If the value is yes, then the application is immediately deleted after being run once.
67957_Wiley_Giguere_CH07x
10/17/2000 4:52 PM
Page 141
The Connected Limited Device Configuration (C LD C) Reference Implementation
141
Debugging Debugging CLDC-based or MIDP-based applications is in many ways similar to returning to the early days of Java. A VM based on the CLDC specification does not have debugging support, so do not expect anything else than the capability to dump program output to a stream. Individual implementations might provide their own debugging facilities, but it is not a requirement of the specification. Because a debugger is rarely available, the best approach to take is to build two versions of your application right from the beginning: a debug version and a production version. Define a Debug class as follows: // For building the debug version public class Debug { public static final boolean on = true; }
Create a second version of the class, but set the on field to false: // For building the production version public class Debug { public static final boolean on = false; }
Because the classes are identical, you will need to place the compiled files in separate directories. When building the debug version of your application, include the first version of the class in the classpath. When building the production version, include the second version of the class. In your code, wrap your debugging or tracing statements as follows: if( Debug.on ){ // place debugging/tracing code here // i.e. calls to System.out.println }
When building the production version of the application, the compiler will then ignore the wrapped code. You can easily add assertion facilities to the Debug class: public class Debug { public static final boolean on = true; public void assert( boolean condition, String message ){
67957_Wiley_Giguere_CH07x
142
10/17/2000 4:52 PM
Page 142
CHAPTER 7 if( on ){ System.out.println( "ASSERTION FAILURE: " + message ); // optionally throw an exception } } }
When you use assertions, however, wrap them as well: if( Debug.on ) Debug.assert( p != null, "p is null" );
Otherwise, you can end up with unnecessary code in the production version of the application.
Internet Resources If you are interested in the CLDC and all things related to it, consider joining the KVM-Interest mailing list. Originally a mailing list for early users of the KVM, the list has since expanded to cover related technologies such as the CLDC and the MIDP. The messages sent to the list are archived and are available from http://archives.java.sun.com/archives/ kvm-interest.html. You can use that URL to join the list and to receive messages as they are posted or in daily digest format. For other CLDC-related resources, refer to the KVMWorld Web site (www.kvmworld.com) or the book’s Web site at www.ericgiguere.com/ microjava.
Chapter Summary In this chapter, we examined how to compile and run J2ME applications on the desktop by using the CLDC. Now, we move on to running Java applications on Palm devices.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 143
CHAPTER
8
Java for Palm Connected Organizers
R
unning Java 2 Micro Edition (J2ME) on the desktop is fine for testing purposes, but at some point you have to run the program on a real device. This chapter shows you how to run J2ME applications on Palm Connected organizers. If you do not own a Palm device, you have no need to worry. You can test your programs by using the Palm OS Emulator, which is a tool that you can download for free.
Using the CLDC with Palm Devices Whether people refer to them as Pilots, Palm Pilots, or Palm organizers, the family of devices from Palm, Inc. is the most successful group of personal digital assistants (PDAs) ever sold. It makes sense that the first port of the CLDC is for the Palm platform, because it has such a large installed base. It’s also the platform for which the KVM was initially developed.
143
67957_Wiley_Giguere_CH08x
144
10/17/2000 5:14 PM
Page 144
CHAPTER 8
A Palm Primer If you have never done any Palm programming or own a different kind of device (such as the PocketPC), this short primer will give you enough background to get started. For more information about Palm programming, consult a book such as Palm Database Programming: The Complete Developer’s Guide or Advanced Palm Programming: Professional Developer’s Guide, both from John Wiley & Sons, Inc. A User’s Perspective There are many models in the Palm Connected organizer family, but they all share a similar form factor. A typical Palm device, the Palm V, was shown in Figure 1.3 in the first chapter and measures about 7.5 cm wide by 11 cm high. This device is small enough to fit comfortably in the palm of your hand, freeing the other hand to press buttons and to use a stylus on the touch-sensitive screen. The screen is 160 pixels wide by 160 pixels high, which is enough for a dozen or so lines of text plus menus. There is no keyboard on the Palm; instead, all text input is entered via the touch screen by using a system of pen strokes called Graffiti. (Die-hard keyboard users can actually buy an external folding keyboard for intensive data entry, as we saw in Chapter 1.) The differences between the various models (starting with the original Pilot and leading up to today’s Palm VII and Palm IIIc) are mostly evolutionary. In general, the more recent the model, the more memory that it has—and the more sophisticated the operating system. All recent models include infrared support, which enables you to beam data and applications from one device to another. The Palm VII is unique in that it has a built-in transceiver for wireless networking via the Palm.Net service. The Palm IIIc is unique because it is the first Palm device with a color screen. Programs written for the original Pilot will usually run unchanged on the newer models. Upward compatibility is an important feature of the Palm family of devices. Another important feature is a Palm device’s capability to synchronize or exchange data with a desktop computer. On the Palm, this function
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 145
Java for Palm Connected Organizers
145
is referred to as HotSync and is easy to perform. You simply place the device in a cradle that is attached to the desktop computer and press the cradle’s HotSync button. The device opens a communication channel with a background program running on the desktop and proceeds to exchange data by using HotSync conduits. A conduit acts as the intermediary between a program installed on the Palm and a program installed on the desktop computer. Conduits enable the Palm’s built-in Address Book and Date Book applications to synchronize with common desktop applications such as Microsoft Outlook or Lotus Notes, enabling you to share addresses, appointments, and more across both devices. Why has the Palm succeeded where other devices have failed? Rather than trying to cram a full-featured operating system into a small form factor, the Palm design team decided to only include the features that were necessary for a minimalist set of useful applications. A Palm device is not a desktop computer and does not claim to be one. Rather, it is a personal, connected organizer. This device has the basic functionality that you need when you are away from a computer and has the capacity to integrate seamlessly with that computer. And now, this device can run Java programs. Palm has been so successful with its devices that other manufacturers are licensing the platform and building new devices that incorporate the Palm operating system’s applications, look, and feel. A Developer’s Perspective Developers write programs for the Palm either because they own one or because they see the large pool of potential buyers created by the Palm platform’s success. Most Palm programs are written in C or C++ by using the CodeWarrior toolset, although developers can also use a port of the open source GNU C/C++ compiler (GCC). C/C++ programmers need to understand a lot of low-level details about the device in order to get started, and we could easily spend this entire chapter discussing them in great detail. Luckily, most of those details are unimportant to Java programmers. All we need is to understand the limitations of the hardware—why it truly qualifies as a small computing device— and how to reset the device. The rest you can pick up as you go along if it interests you.
67957_Wiley_Giguere_CH08x
146
10/17/2000 5:14 PM
Page 146
CHAPTER 8
The Basic Hardware
Palm devices are battery-operated computing devices (using either two AAA batteries or built-in rechargeable batteries) that run on a Motorola DragonBall processor, which is a low-power derivative of the MC68000 chip found in the early Macintosh and Amiga computers. The Dragon Ball is far from speedy, and the most recent Palm models run at about 20MHz. To save power, a Palm device switches between three modes of operation: sleep mode, doze mode, and running mode. The latter occurs when the device is actively running an application. If the device is waiting for user input, it places itself in doze mode—halting the processor until an interrupt awakens it. Sleep mode turns everything off except the memory chips, the clock, and some low-level circuitry. For this reason, a typical Palm device can last for two weeks without having to replace or recharge the batteries (most of its time is spent in doze or sleep mode).
A Warning for Developers If you keep the device in running mode, its batteries will drain fairly quickly. Do not write Java programs that hog the Central Processing Unit (CPU). The usual warnings about avoiding busy wait loops and other expensive programming practices apply even more to the Palm platform and to similar devices.
The Operating System
The operating system on a Palm device is referred to simply as Palm OS. The current version of Palm OS at this writing is 3.5. On the original models, the operating system was stored in read-only memory (ROM), although a trap facility (operating system functions are called through a dispatch table) made it possible to install minor bug fixes. The newer models store the operating system in Flash memory, enabling them to be upgraded to the latest version by simply downloading an update from Palm’s Web site.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 147
Java for Palm Connected Organizers
147
Palm OS uses threads internally, but Palm applications only run on a single thread. In fact, only one application runs at a single time. Users might think that they are merely switching between applications, but in fact, one application is shutting down (after saving its state) and another is starting up (and restoring its state). This programming is clever, and the emphasis is on responsiveness and that instant-on feeling.
Multiple Threads and Java A single thread of execution does not mean that Java programs cannot be multithreaded. Remember that a Java interpreter can do the necessary context switching itself. A single thread to run the interpreter is all that the CLDC requires.
Memory Model
The Palm OS memory model is a bit unusual and quite frustrating to the average developer—especially to a Java developer. A Palm device partitions its RAM into two heaps. The first heap is called the dynamic heap, and it occupies the first 64K to 256K of available memory, depending on the model and the version of the operating system. This RAM stores the application’s runtime heap, the application’s runtime stack, and the system’s global variables. It also stores the TCP/IP protocol stack (32K in size) if networking is enabled. Its contents do not survive a device reset, and the application heap and stack are of course freed whenever the application terminates. The remaining RAM in the device is in the storage heap. Data placed in the storage heap is organized into databases of records (for ordered data) or resources (for unordered data). Palm OS has no notion of a file system, so everything is stored as a database—including the applications themselves. As you might expect, the contents of a database are preserved when the device is reset, except when a hard reset is performed (refer to the following paragraphs). Databases are also writeprotected, modifiable only through special Palm OS APIs—thus, writing to storage memory is significantly slower than writing to dynamic memory.
67957_Wiley_Giguere_CH08x
148
10/17/2000 5:14 PM
Page 148
CHAPTER 8
Prior to Palm OS 3.0, the size of the dynamic heap was no larger than 64K. Palm OS 3.0 increased the size to 96K, of which 32K was used by the TCP/IP protocol stack—leaving only 64K for application and system use (even if the device has 8MB of RAM). In Palm OS 3.5, the size of the dynamic heap varies based on the amount of RAM in the device. If the device has fewer than 2MB of RAM, the dynamic heap is 64K in size. If the device has 2MB or more but fewer than 4MB of RAM, the dynamic heap is 128K; otherwise, the size of the dynamic heap is 256K. Always subtract 32K from the available memory if networking is enabled. Because the amount of dynamic memory is fixed, the size of an application’s runtime heap is quite limited—even if there are several megabytes of free storage memory. Any requirements for further memory must be met by using storage memory, perhaps by implementing a simple virtual memory scheme and paging data in and out of dynamic memory as required. As of this writing, the KVM running on the Palm does not support any memory paging, and all runtime objects are allocated from the dynamic heap. Resetting the Device
If your Palm device ever locks up, you will need to reset it. There are three kinds of reset: soft, modified soft, and hard. A soft reset clears the contents of the dynamic heap and resets the state of the operating system. The contents of storage memory are preserved. In order to perform a soft reset, press the tip of a straightened paper clip or the unscrewed top of a stylus gently into the Reset hole in the back of the device. A modified soft reset is a soft reset that does not notify the applications that the operating system has been reset. Normally, applications are notified by the operating system about significant events. If an application crashes or locks up during this notification, it can freeze the system. To perform this reset, perform a soft reset while pressing and holding down the scroll-up button. A hard reset clears the contents of dynamic and storage memory before resetting the operating system. You will lose any applications that were installed on the device (other than the built-in applications). You should not perform this operation lightly, so be sure to back up your data first
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 149
Java for Palm Connected Organizers
149
if possible. To perform this reset, press and hold down the power button, push the paper clip or unscrewed stylus top into the Reset hole, remove it, and then release the power button. You will be asked to confirm the hard reset by pressing the scroll-up button. The Palm OS Emulator The Palm OS Emulator (POSE) is an incredibly useful tool for any kind of Palm programming. This emulator enables you to test and debug your applications on your desktop computer without having to install them on an actual device. The development cycle is much faster if you use POSE for your initial testing. POSE is free for downloading from the Palm OS development Web site at www.palmos.com/dev/tech/ tools/emulator. The version described here is 3.0a5, but the emulator is constantly updated—so check the Web site regularly for newer versions. POSE is available for Microsoft Windows, Macintosh, or Linux. POSE is a true emulator, not a simulator. It requires a Palm OS ROM image to work, which you must obtain from a real Palm device or through the Palm OS developer program. Testing with different ROM images is recommended in order to ensure that differences in operating system version and available memory do not cause your application to terminate unnecessarily. POSE provides a utility to obtain the ROM image from a cradled device. To obtain other ROM images, join the free Palm developer program, the Solution Provider Program (SPP), by registering at www.palmos.com/dev/program. Residents of the United States will have immediate access to the ROM images, but residents of other countries will have to sign and send in some simple legal forms before being granted access. A screen shot of POSE running on Windows is shown in Figure 8.1. Its menus enable you to configure POSE to use a specific ROM image with a specific amount of RAM, to reset the device, to initiate a HotSync, to install an application, and to run some random user interface tests called Gremlins. Palm applications are stored in files ending with the .prc extension, and any associated data files end with the .pdb extension. These files must be installed in POSE by using the Install Application/Database menu. If your application does not appear in the Launcher (the Palm OS desktop) after installing it, activate one of the standard applications
67957_Wiley_Giguere_CH08x
150
10/17/2000 5:14 PM
Page 150
CHAPTER 8
Figure 8.1 The Palm OS Emulator in action.
(such as the Address Book) and then return to the Launcher. The application should then be visible.
Installing the Palm CLDC The Palm CLDC implementation is in a separate ZIP file. Like the CLDC reference implementation, it is available free for downloading from Sun Microsystems’ Web site at www.sun.com/software/communitysource/ j2me/. You must still download and install the reference implementation first, however. The Palm port is an overlay that adds new files and directories to the basic CLDC installation. The overlay includes the following elements: ■■
■■
The Palm port of the KVM (KVM.prc) and the utility for capturing the output of the System.out and System.err streams (KVMutil.prc). These files are installed in the bin directory. Compiled versions of the samples, packaged as Palm executables. These files are also installed in the bin directory.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 151
Java for Palm Connected Organizers ■■
■■
■■
151
Two Java-based utilities, MakePalmApp and ConvPRCtoJAR, for packaging Java applications as Palm executables and vice-versa. You can find the source for these in the tools\palm directory. Palm-specific versions of the CLDC classes as required, with complete source code Complete source code for KVMutil and the Palm version of the KVM
After unzipping the files, you will need to compile the MakePalmApp and ConvPRCtoJAR utilities, bundling them into a JAR file called palmdb.jar. Use something similar to the following: cd %KVM_HOME% mkdir lib mkdir lib\classes cd tools\palm\src\palm\database javac -d %KVM_HOME%\lib\classes *.java copy Wrapper.prc %KVM_HOME%\lib\classes\palm\database copy DefaultTiny.bmp %KVM_HOME%\lib\classes\palm\database cd %KVM_HOME%\lib\classes\palm jar cvf ..\palmdb.jar .
Note that MakePalmApp and ConvPRCtoJAR are J2SE-based applications that run on your desktop. They are not J2ME applications. The final step is to install KVM.prc, KVMutil.prc, and the other .prc files in the bin directory into the POSE or on the device. Palm OS 3.01 or higher is required to run the KVM, so for POSE, the ROM image of a recent device such as the Palm V or the Palm VII will do fine.
Running the Samples Take some time now to run through the samples at least once. Notice how there is a delay between the time that you tap on the sample’s icon and when it actually starts. This delay is unavoidable, unfortunately, as the KVM loads and verifies the class files required by the application. It would be much worse if J2SE-style verification were performed. If you are using the emulator and have access to a real device, this point would be a good time to load the samples onto the device. Some of the games are not too playable when run in the emulator, either because the emulator runs them too quickly or because they depend on button presses that are hard to simulate with a mouse.
-
67957_Wiley_Giguere_CH08x
152
10/17/2000 5:14 PM
Page 152
CHAPTER 8
KVMutil The KVMutil application lets you view the contents of the System.out and System.err streams, either as the Java program runs or after it is done running. This application also enables you to control the amount of heap space that applications allocate. To use KVMutil, tap on its icon. You can also tap on the KVM icon and achieve the same effect. You will see the screen shown in Figure 8.2, and this screen enables you to control the following settings: Show heap stats. If checked, the KVM displays how much heap is allocated when it starts. Max heap size. It configures how much of the dynamic memory heap is allocated by the KVM when it starts Screen output. If set to a non-zero value, the KVM displays System. out and System.err output at the top of the screen when it runs an application. The value is the number of lines to display.
Figure 8.2 The KVMutil screen.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 153
Java for Palm Connected Organizers
153
Save output. If this option is checked, characters written to System.out and System.err are saved by the KVM to a Palm database. When the program is done running, start KVMutil again and press the View output button to see the stream contents. If you are running an application with the emulator, console output is also echoed to the STDOUT.txt and STDERR.txt files in the emulator’s installation directory. This action occurs whether or not KVMutil is set to save the output.
Revisiting the Hello World Application Let’s revisit the HelloWorld application. If you recall, this application is trivial: public class HelloWorld { public static void main( String[] args ) { System.out.println( "Hello, world!" ); // Wait for ten seconds try { Thread.sleep( 10000 ); } catch( InterruptedException e ){ } } }
We compile and preverify this program by using the same syntax as before: javac -g:none -bootclasspath %KVM_HOME%\bin\api\classes -classpath %KVM_CLASSPATH% -d %KVM_TMP_DIR% HelloWorld.java %KVM_HOME%\bin\preverify -d %KVM_OUTPUT_DIR% -classpath %KVM_CLASSPATH%;%KVM_HOME%\bin\api\classes %KVM_TMP_DIR%
Instead of running the program directly, however, we must transform it into a Palm executable by using the MakePalmApp tool:
67957_Wiley_Giguere_CH08x
154
10/17/2000 5:14 PM
Page 154
CHAPTER 8 java -classpath %KVM_HOME%\lib\palmdb.jar palm.database.MakePalmApp -v -bootclasspath %KVM_HOME%\bin\api\classes -icon %KVM_HOME%\samples\icons\default.bmp -smallicon %KVM_HOME%\samples\icons\DefaultTiny.bmp -classpath %KVM_OUTPUT_DIR%;%KVM_CLASSPATH% HelloWorld
You will definitely want to define a batch file or shell script/alias to run this rather ugly command line. This line looks confusing at first glance. Remember that the MakePalmApp tool is a Java program, so the first part of the command line—“java –classpath %KVM_HOME%\lib\ palmdb.jar palm.database.MakePalmApp”—is just invoking the tool. If you put the palmdb.jar file into your CLASSPATH (which is safe to do, because MakePalmApp is a J2SE application), you can just use “java palm.database.MakePalmApp” to invoke it. ■■
■■
■■
■■
■■
The arguments to MakePalmApp represent the remainder of the command line, and these arguments are quite numerous: -v turns on verbose output so that you can see what MakePalmApp is doing. Strangely enough, repeating the option—using -v -v— increases the amount of output. -bootclasspath path is the path to the CLDC classes (the ones that are already included in the KVM.prc file). -icon path and -smallicon path are paths to the application’s icons. Each application needs two icons: a large 22-by-22 icon (which will be automatically adjusted to a 32-by-32 size) and a smaller 15-by-9 icon. The icons can be in Windows bitmap format (.bmp), portable bitmap format (.pbn) or Palm OS bitmap format (.bin). For the HelloWorld application, just use any of the bitmap files in the samples\icons directory. If the bitmap is too large for the small icon, MakePalmApp will convert it to a good size. -classpath path is the path to the application classes. If this path is omitted, the current directory is used. Note that the CLASSPATH environment variable is always ignored, so you must explicitly set the classpath with this option.
The final argument is the name of the application’s main class. This name is usually all that MakePalmApp needs to determine which classes are to be included in the generated executable. If classes are loaded dynamically at run time by using Class.forName, however,
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 155
Java for Palm Connected Organizers
155
you should include those classes as additional arguments to MakePalmApp immediately after the main class. Once you have generated the HelloWorld.prc file, install it on the device or in the emulator. Before running it, tap the KVMutil icon and ensure that the Screen output setting is set to five lines of output. Return to the application launcher and run the HelloWorld application. You should see a display like the one in Figure 8.3. Now, take the HelloWorldUI spotlet and run it through the MakePalmApp process. The output is shown in Figure 8.4, and this output is of course identical to what we saw in Figure 7.2.
Additional MakePalmApp Options Apart from the options that we just discussed, there are additional options that you can (and should) specify when building a Palm executable with MakePalmApp:
Figure 8.3 Running the HelloWorld application.
67957_Wiley_Giguere_CH08x
156
10/17/2000 5:14 PM
Page 156
CHAPTER 8
Figure 8.4 Running the HelloWorldUI spotlet.
■■
■■
■■
-name name sets the application’s short name. The short name is displayed in the launcher underneath the application’s icon. If this option is omitted, MakePalmApp uses the name of the main class without the package name, truncating it if necessary. -networking indicates that the application is network-enabled. A network-enabled application initializes the TCP/IP stack when it starts, making it possible to open socket connections to the external world. If this flag is not specified, the KVM assumes that the application will not perform any network connectivity and adds the 32K that is normally used by the TCP/IP protocol stack to the application’s runtime heap. Without this flag, any attempt to connect will fail, because the KVM leaves no dynamic memory for the protocol stack. -longname name is the full name of the application. This name is displayed by Palm OS when it prompts you to select an application, such as when it asks you which application to delete. Palm OS limits the length of this name to 31 characters. If this option is omitted, MakePalmApp uses the full class name.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 157
Java for Palm Connected Organizers ■■
■■
■■
■■
157
-version versionstring is the version of the application—a string of the form x.y—where x is the major version and y is the minor version. The version numbers for installed applications are accessible from the application launcher’s menu. If this option is omitted, it defaults to 1.0. -output path specifies the name of the output file. If omitted, it defaults to the name of the main class with a .prc extension. -resource path includes the specified file in the executable. At run time, the program can access the file by using the Class.getResourceAsStream method. -creator creatorID sets the application’s creator ID, which is a four-character (ASCII, not Unicode—they are eight-bit characters) value that uniquely identifies the application. If this option is omitted, MakePalmApp generates one automatically; however, there are no guarantees that a generated creator ID will not conflict with another application.
Of all of the options, the –creator option is the most important. All Palm applications must have a unique creator ID. Creator IDs are registered with Palm, Inc. by using a simple Web-based form at www.palmos.com. If you are going to distribute your application to anyone, be sure to register a creator ID for the application. For testing purposes, you can let MakePalmApp generate one for you. A final option is available. If you have a JAR file that you want to convert to a Palm executable (.prc), use the –JARtoPRC jarfile mainclass option.
Additional APIs Both the reference and Palm CLDC implementations come with additional APIs that are not found in the CLDC specification, such as the user interface classes. These additional APIs are there for two reasons: one, to extend the CLDC with enough functionality in order to make it useable; and two, to serve as guides and examples for device manufacturers who are interested in implementing the CLDC on their own platforms. Understand, however, that the additional APIs can be changed
67957_Wiley_Giguere_CH08x
158
10/17/2000 5:14 PM
Page 158
CHAPTER 8
or removed by Sun Microsystems at any time. Only the additional APIs that are defined by profiles (such as those defined by the MIDP) or that are otherwise guaranteed support by the J2ME implementer should be used. But because no profile supports Palm devices as of yet, the additional non-CLDC APIs are the only game in town for now for that particular platform. With that warning aside, let’s take a look at what these classes can do.
The User Interface As we already mentioned, the CLDC implementations include a set of user interface classes for building spotlets, which are simple applications that have a Palm-like user interface. These classes were, in fact, originally developed for use on Palm devices and were ported to Windows and Unix for use with a simple Palm device simulator. Spotlets are simpler than MIDlets, much more limited, and much more devicespecific. All of the classes discussed here are part of the com.sun. kjava package. The Spotlet Model A spotlet is a class that extends com.sun.kjava.Spotlet. The Spotlet class is roughly analogous to the Canvas class defined by the MIDP: it receives low-level input events and provides a blank slate for drawing on the display. An application can create and use multiple spotlets to display different windows. Like a Canvas, a spotlet is responsible for painting itself, including any user interface controls. Unlike the MIDlet model, however, the spotlet model does not generate paint events. You are responsible for tracking and redrawing any changes to the display. Multiple spotlets can share the display at a single time, because it is up to you to call their update routines in the correct order. There is no concept of visibility. You either draw a spotlet or you do not. Input Events Although multiple spotlets can draw on the display, only one spotlet at a time receives the input focus. This spotlet is referred to as the current spotlet. To make a spotlet the current spotlet, call its register method:
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 159
Java for Palm Connected Organizers
159
Spotlet s = new MySpotlet(); s.register( Spotlet.NO_EVENT_OPTIONS );
Calling register within the spotlet’s constructor, along with the initial display update, is normal. To remove the input focus, call the unregister method (although normally, this action is not necessary). The register method performs this action automatically when activating a new spotlet. The register method takes one of two parameters: NO_EVENT_OPTIONS or WANT_SYSTEM_KEYS. Both are constants defined by the Spotlet class. Some of the input events on a Palm device are normally handled by the system itself and are referred to as system events. Pressing the Address Book button, for example, shuts down the current application and launches the Address Book. You can trap some of these system events (specifically, the raw key-press events that trigger them) by using WANT_SYSTEM_KEYS when registering the spotlet. The missiles.Missiles sample, for example, uses WANT_SYSTEM_KEYS to use the device’s buttons as a crude game controller. For most applications, use NO_EVENT_OPTIONS.
A Warning about WANT_SYSTEM_KEYS Several of the buttons on a Palm device cause the current application to terminate and a new application to start. Internally, what happens is that the system traps the button press and queues a special event that asks the application to stop. If you register a spotlet with WANT_SYSTEM_KEYS, the system never traps the button press and never generates the stop event. Unless you provide a way to terminate the application by calling System.exit in response to user input, the application runs indefinitely. The only way to stop it is by resetting the device.
Individual events are sent to the current spotlet by directly invoking methods on the class—again, much like the original AWT event model. The com.sun.kjava.Spotlet class defines the following methods (any or all of which the spotlet can override in order to process the events): ■■
public void keyDown( int keyCode ) is called when a Graffiti character is inputted or when a button is pressed. The keyCode parameter is the Palm key code for the character (in ASCII) or
67957_Wiley_Giguere_CH08x
160
10/17/2000 5:14 PM
Page 160
CHAPTER 8
button press. The Spotlet class defines constants for the common buttons that an application would intercept: PAGEUP, PAGEDOWN, CALCICON, MENUICON, KEY_HARD1, KEY_HARD2, KEY_HARD3, KEY_HARD4, and KEY_POWER. Note that the last five button events are trapped only when the input focus option is WANT_SYSTEM_ KEYS. ■■
■■
■■
■■
public void penDown( int x, int y ) is called when the pen touches the screen. The x and y coordinates indicate where the touch occurred and are relative to the top-left corner of the display. public void penMove( int x, int y ) is called when the pen moves while it touches the screen. The x and y coordinates indicate the current pen position. public void penUp( int x, int y ) is called when the pen is removed from the screen. public void beamReceive( byte[] data ) is called when data is received on the infrared port. The byte array holds the data that was received.
As you can see, the events that a spotlet supports are basic. Also, no events ever get routed to specific user interface controls; rather, it is always up to the spotlet to determine (with the control’s help) whether a control is interested in a specific event and to call its methods accordingly. Drawing Because there are no paint events, all drawing is done in response to user input or application-state changes. The graphics subsystem defines a Graphics class with a few basic methods for drawing lines and text on the screen. The graphics capabilities are limited when compared to those of the MIDP or J2SE. To obtain a Graphics object for drawing, call the static getGraphics method. This method returns the one-and-only Graphics object in the system: Graphics g = Graphics.getGraphics();
Implementing the object as a singleton reduces the number of memory allocations required by the graphics subsystem.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 161
Java for Palm Connected Organizers
161
Once you have the Graphics object in hand, you can draw anywhere on the display at any time: // Demonstrate basic drawing commands Graphics g = Graphics.getGraphics(); g.clearScreen(); // x1, y1, x2, y2, mode g.drawLine( 0, 0, 159, 159, g.PLAIN ); // x, y, w, h, mode, borderType g.drawBorder( 2, 2, 156, 156, g.PLAIN, g.SIMPLE ); // x, y, w, h, mode, cornerDiameter g.drawRectangle( 10, 10, 140, 140, g.INVERT, 0 ); g.drawString( "Some text", 0, 0 ); g.drawString( "Some inverted text", 0, 20, g.INVERT ); g.drawString( "Some erased text", 0, 40, g.ERASE );
There is no support for color on the KVM, although a version of the KVM with color support is available from the creators of kAWT (discussed later in this chapter). As well, only one font is supported. A Bitmap class is used to represent Palm OS black-and-white bitmaps. Controls The KVM does include classes for drawing a number of user interface controls. These controls have a Palm look and feel but are written entirely in Java. No native peers are used (as in AWT). The supported controls are as follows: Button. Draws text-based or bitmap-based buttons CheckBox. Draws labeled checkboxes Dialog. Displays a pop-up window of text. This spotlet automatically creates a TextBox or ScrollTextBox as appropriate and waits for the user to dismiss it. The owner of the dialog (an object that implements the DialogOwner interface) is notified when the dialog is dismissed. HelpDisplay. Displays a window of help text before starting an application. This spotlet is similar to the Dialog class, but it dynamically creates an instance of a given Spotlet subclass when dismissed. RadioButton. Draws labeled radio buttons. Radio buttons can be grouped together by using the RadioGroup class in order to ensure
67957_Wiley_Giguere_CH08x
162
10/17/2000 5:14 PM
Page 162
CHAPTER 8
that only one button with the group is selected. The RadioGroup is not a user interface control, however. ScrollTextBox. Extends TextBox by adding a VerticalScrollBar to scroll the text SelectScrollTextBox. Extends ScrollTextBox in order to allow the selection/deselection of a line of text Slider. Displays a horizontal slider to select an integer value within a fixed range of values TextBox. Displays one or more lines of non-editable text. The text is wrapped as necessary based on the space or new-line characters in the string. TextField. Displays a single line of labeled, editable text ValueSelector. Displays and lets the user select an integer value in a way similar to a spin control VerticalScrollBar. Draws a vertical scroll bar. The owner of the scroll bar (an object implementing the ScrollOwner interface) is notified whenever the user changes the scroll bar’s value. More sophisticated user interface behaviors are handled by writing custom controls that might or might not use one of the predefined controls as starting points. Remember that there are no paint events and no event delegation in the spotlet model. To draw or refresh a control, call its paint method. To handle user input, call an appropriate method—passing in the key that was pressed or the position of the pen. Consider this simple example: import com.sun.kjava.*; public class PressMe extends Spotlet { public static void main( String[] args ) { new PressMe(); } private Button button = new Button( "Press me!", 1, 80 ); public PressMe() { register( NO_EVENT_OPTIONS );
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 163
Java for Palm Connected Organizers
163
Graphics.getGraphics().clearScreen(); button.paint(); } public void penDown( int x, int y ) { if( button.pressed( x, y ) ){ System.out.println( "You pressed me!" ); } } }
When the PressMe class receives a pen-down event, it forwards it to the button’s pressed method. If the button is disabled or the event occurs outside its boundaries, pressed returns a value of false. Otherwise, it inverts the button, waits a tenth of a second, redraws the button, and returns a value of true. All of the controls are used similarly, although they expose different event-handling methods.
Databases Palm OS databases are accessed by using the com.sun.kjava. Database class, which is basically a wrapper class whose methods invoke their Palm OS equivalents. The CLDC reference implementation provides a crude simulation of Palm OS databases by creating files in the current directory. Understanding Palm Databases A Palm database is a set of memory blocks allocated from the storage heap and managed as a single entity by the operating system. The memory blocks are allocated independently and can exist throughout the storage heap. The only restrictions are that no block can exceed 64K in size and that all of the blocks must reside on the same memory card.
What Is a Memory Card? In a Palm device, RAM and ROM are packaged together on a piece of hardware called a memory card. In theory, there can be several memory cards per device, but in practice, there is only one (referred to as card 0).
67957_Wiley_Giguere_CH08x
164
10/17/2000 5:14 PM
Page 164
CHAPTER 8
Palm databases come in two formats: resource and record. Resource databases store unordered memory blocks, while record databases store ordered memory blocks. Record indexes start at 0. Databases also have creator IDs, types, and names. The creator ID identifies the application that created the database. The type is a fourcharacter (32-bit) value identifying the purpose of the database (separate from the kind of database it is—resource or record). The name of a database must be fewer than 32 characters long and must be unique among all of the installed databases (and applications—an application is really just a resource database). An easy way to ensure uniqueness is to include the creator ID in the name. Using Databases in Java Palm OS defines a number of APIs for dealing with databases, but the Database class provides only the most basic functionality. To create a database, use the static create method: String name = ....; // up to 31 characters long int creatorID = ....; // 4-character value int typeID = ....; // 4-character value boolean ok = Database.create( 0, name, creatorID, typeID, false );
The last parameter indicates whether or not to create a resource database. You should always set it to false, because the Database class does not expose the necessary Palm OS functionality to properly access resource databases. The creator ID and type parameters must be 32-bit values. Take the four-character ASCII string and convert each character to its two-digit hex value. Combine these values to form an eight-digit hex value. For example, ABCD becomes 0x41424344, because A = 0x41, B = 0x42, C = 0x43, and D = 0x44. The creator ID must match that of the application in order to ensure that the database is deleted whenever the application itself is deleted. The type can be any sequence of four characters, providing that at least one of them is upper-case. To open a database, create a Database object identifying the database in question by its type and creator ID: Database db = new Database( typeID, creatorID, Database.READWRITE ); if( !db.isOpen() ){ // error, couldn’t open database! }
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 165
Java for Palm Connected Organizers
165
A database can be opened for reading, writing, or both. Once the database is open, you can count the number of records that it holds by calling getNumberOfRecords: int count = db.getNumberOfRecords();
To read a database record, use getRecord: byte[] data = db.getRecord( index );
Similarly, to write an existing database record by using setRecord: byte[] data = ....; db.setRecord( index, data );
To add a new record to the database, use addRecord: db.addRecord( data );
When you are done, call the close method to close the database. (Note that isOpen still returns true after calling the close method, although the database is not open.) No other APIs are available for database manipulation. The Database class provides only the most basic support for Palm OS databases.
Network Connectivity Technically, the Generic Connection framework of the CLDC does not provide any communication drivers, leaving them up to the profiles to define. Both the reference implementation and the Palm port provide sample communication drivers, however, in order to demonstrate their use. The Connector Class The heart of the Generic Connection framework is the javax.microedition.io.Connector class, which is how a CLDC-based application obtains a Connection object. The reference implementation of Connector uses the protocol name in the connection string to dynamically load a factory class that is capable of creating the appropriate
67957_Wiley_Giguere_CH08x
166
10/17/2000 5:14 PM
Page 166
CHAPTER 8
Connection object. In other words, given a connection string of the form protocol://info, it looks for a class called com.sun.cldc. io.platform.protocol.Protocol, where platform identifies the platform that is being used. The reference implementation uses the j2me platform, so if you look in the api\com\sun\cldc\io\j2me directory, you will see that it supports the following protocols: ■■ ■■
■■
datagram for datagram (UDP) communication debug for debugging output. The System.out and System.err streams use this protocol. events for obtaining input events from the windowing system. A thread started by the Spotlet class uses this stream to fetch and dispatch events.
■■
resource for loading files in the class path
■■
serversocket for opening server sockets
■■
socket for opening client sockets
■■
storage for reading and writing to files
■■
testhttp for performing simple HTTP requests
■■
translate for reading localized strings (experimental)
For full documentation on each protocol, read the comments in the Protocol.java file in the appropriate directory. Most communication drivers use native functions to do the actual connecting by using the appropriate system facilities. Note that no implementation of the CLDC is required to support all or any of these communication drivers. An implementation can also add its own protocols. The Palm port of the CLDC defines the following protocols, for example: ■■
comm for direct serial port communication
■■
http for an HTTP request
■■
https for HTTPS requests (HTTP that uses secure sockets)
■■
storage for reading and writing to databases. The driver uses the com.sun.kjava.Database class to read from and write to a database.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 167
Java for Palm Connected Organizers
167
The platform for these protocols is palm, so the source code for them is found in the subdirectories of api\com\sun\cldc\io\palm. If a particular protocol cannot be found by using the palm platform, a second try is made using the j2me protocol. HTTP Connections Higher-level protocols are more likely to be supported across different implementations. For example, any device that supports the MIDP must support HTTP connections. A good place to start your experiments with the Generic Connection framework, therefore, is with the HTTP protocol. To make an HTTP connection, use a conventional URL, as in the following: import java.io.InputStream; import javax.microedition.io.Connector; InputStream in; in = Connector.openInputStream( "http://localhost/index.html" );
For the reference CLDC implementation, replace the http protocol with testhttp. The Palm port includes an additional sample called KvmHttpTest that demonstrates how to make simple HTTP and HTTPS connections in order to read files from Web sites. When using the HTTP or HTTPS protocols in your own Palm applications, be sure to use the –networking option when invoking MakePalmApp in order to ensure that networking is enabled when the application runs.
The Tic-Tac-Toe Example Let’s take the tic-tac-toe game model that we developed back in Chapter 3 and build a complete spotlet around it as a further example of how to use Java on Palm devices. You will find complete listings for all of the classes in Appendix A and on the accompanying CD-ROM. The CD-ROM also contains the compiled version of the game and a set of batch files to build it. Refer to the CD-ROM for complete instructions.
67957_Wiley_Giguere_CH08x
168
10/17/2000 5:14 PM
Page 168
CHAPTER 8
Usage The tic-tac-toe game is found in the file TicTacToe.prc. Install this file on your device or in the emulator, and tap on its icon. You will see an empty grid. You are the first player, and the device is the second player. You start the game by tapping on any of the empty cells in the grid to display an X. The device then responds by selecting another cell and displaying a stylized O, as shown in Figure 8.5. After the device has selected a cell, it is your turn again. This interaction continues until all of the cells are filled or until either player completes a row. The game then ends and a dialog announces the winner, as shown in Figure 8.6. Dismiss the dialog to start a new game.
How It Works The tic-tac-toe game is a fairly simple spotlet. This spotlet consists of four classes: TicTacToe, TicTacToePlayer, TicTacToeModel, and TicTacToeModelListener. The latter two were described in
Figure 8.5 The Tic-Tac-Toe game screen.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 169
Java for Palm Connected Organizers
169
Figure 8.6 The winner.
Chapter 3. What is new are the TicTacToe and TicTacToePlayer classes. TicTacToe is the main class. Besides extending the Spotlet class, it also implements the DialogOwner and TicTacToeModelListener interfaces: import com.sun.kjava.*; import com.ericgiguere.j2mebook.models.*; public class TicTacToe extends Spotlet implements DialogOwner, TicTacToeModelListener { ...... }
The entry point to the spotlet is of course the main method, which creates an instance of the spotlet. The constructor is as follows: public TicTacToe(){ register( NO_EVENT_OPTIONS ); Graphics.getGraphics.clearScreen(); model = new TicTacToeModel();
67957_Wiley_Giguere_CH08x
170
10/17/2000 5:14 PM
Page 170
CHAPTER 8 model.addListener( this ); model.addListener(new TicTacToePlayer(TicTacToeModel.PLAYER_2)); model.newGame(); }
The constructor creates a model to hold the game state and registers two listeners for the model: the spotlet itself (which will draw the grid and respond to user input) and an instance of the TicTacToePlayer class, which we will describe later. The constructor’s last action is to start a new game, which will invoke the gameStarted method on each of the model’s listeners. TicTacToe’s gameStarted method calculates the cell dimensions and draws the grid and the contents of each cell by calling the paint method. Cell information is stored in an inner class called Cell, one instance of which is created for each cell in the grid. Pen-down events are the only user input to which the game responds: public void penDown( int x, int y ){ if( model != null && model.isGameStarted() ){ for( int i = 0; i < numCells; ++i ){ if( cells[i].contains( x, y ) ){ model.setCellState( i, TicTacToeModel.PLAYER_1 ); return; } } } }
Whenever the user taps the screen, penDown determines which cell is being selected and selects it for Player 1. If the cell is empty, the model will change the cell’s state and then send a gameUpdated notification to the listeners. TicTacToe updates its internal state and repaints the grid: public void gameUpdated( TicTacToeModel model,int index,int value ){ cells[index].state = value; paint(); }
If the game is over, the model calls the gameOver method in order to announce the winner: public void gameOver( TicTacToeModel model ){ String text;
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 171
Java for Palm Connected Organizers
171
switch( model.getWinner() ){ case TicTacToeModel.PLAYER_1: text = "Player 1 wins!"; break; case TicTacToeModel.PLAYER_2: text = "Player 2 wins!"; break; default: text = "A tie!"; break; } Dialog d = new Dialog( this, "Game Over", text, "OK" ); d.showDialog(); }
The dialog displays the text until dismissed by the user, at which point the main class’s dialogDismissed method is called: public void dialogDismissed( String title ){ register( NO_EVENT_OPTIONS ); model.newGame(); }
This method re-registers the spotlet to receive input events and starts a new game. There is not a lot of complicated user interface code in this sample. Mostly, it is just a matter of drawing lines on the screen in response to user input. The only tricky part is that there is no method to draw circles for the O characters, so the cell painting resorts to drawing a raised (shadowed) rectangle instead.
The Automatic Player The logic for playing tic-tac-toe is contained in the TicTacToePlayer class. Like the TicTacToe class, the TicTacToePlayer class implements TicTacToeModelListener and is the recipient of game events. When you (as Player 1) select a cell in the grid, the TicTacToePlayer representing Player 2 receives a gameUpdated notification. It asks the model for the row totals and looks for any rows that it can fill with a third character in order to win the game. Failing that, it then looks for any rows that Player 1 can use to win the game and that it can then block. Otherwise, it selects a cell at random. Again, refer to
67957_Wiley_Giguere_CH08x
172
10/17/2000 5:14 PM
Page 172
CHAPTER 8
the code in Appendix A for details. The automatic player shows the flexibility that you can get by cleanly separating the model from the rest of the application.
Third-Party Tools and Extensions A few tools and extensions for the Palm CLDC are available from nonSun sources and deserve some investigation on your part.
kAWT Perhaps the best-known KVM extension is kAWT, which is a simplified version of AWT that runs on the KVM. Unlike the original AWT, kAWT requires no native code. All of its drawing is done by using the graphics subsystem exposed by com.sun.kjava.Graphics. kAWT is a commercial product from Stefan Haustein and Michael Kroll but is free for private or educational use. You can download kAWT from the kAWT Web site in Germany: www.kawt.de, or from the CD-ROM accompanying this book. The latest version of kAWT as of this writing is 0.90. What kAWT does is implement a subset of the AWT classes from J2SE. Programs written with kAWT will run unchanged on J2SE, although the reverse is not true unless you are careful to use only the classes and methods that kAWT supports. Figure 8.7 shows a screen shot from the sample application included with kAWT. The disadvantage to using kAWT is that it increases the size of your programs. The full set of kAWT classes adds about 100K to a program. The footprint is reduced somewhat by installing the classes as Palm OS shared libraries, but it is still a significant increase in overall program size. Also, of course, the more classes there are to load, the longer the program startup will take.
Color KVM The creators of kAWT have also ported the KVM to Palm OS 3.5 in order to take advantage of the latter’s new color support. You can get the color KVM from the same site, www.kawt.de.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 173
Java for Palm Connected Organizers
173
Figure 8.7 A kAWT application.
JBuilder Handheld Express At this writing, Borland has released a beta version of its Handheld Express, which is an add-on to its JBuilder Java development tool. Handheld Express adds support for the Palm port of the CLDC to JBuilder Foundation 3.5. Both are available as free downloads (after registering with Borland) from the JBuilder Web site at www.borland. com/jbuilder/hhe. Once you have followed the installation instructions (which includes getting the CLDC reference and Palm implementations from the Sun Microsystems Web site), JBuilder can edit and compile J2ME programs. Visual form/screen editing is not available, nor is debugging. A simple Spotlet wizard, shown in Figure 8.8, does help you get started, though.
Jbed MicroEdition (CLDC) At the 2000 JavaOne Conference, a Switzerland-based company called esmertec compared Java programs running with its Jbed MicroEdition
67957_Wiley_Giguere_CH08x
174
10/17/2000 5:14 PM
Page 174
CHAPTER 8
Figure 8.8 JBuilder Handheld Express Spotlet wizard.
(CLDC) runtime environment against the same programs running with the reference implementation of the KVM. The Jbed programs ran noticeably faster and caught the eye of J2ME enthusiasts who had already run up against the KVM’s memory and speed limitations. How had someone been able to write such a fast VM? The company claims that Jbed programs run faster because the VM compiles Java bytecodes to native code, just like the just-in-time compiler used by the classic J2SE VM. This compilation can occur on the desktop computer that hosts the Jbed integrated development environment or dynamically on the device itself. As well, Jbed programs do not suffer from the same memory limitations as the KVM. An early beta of Jbed looks quite promising. The product should be out by the time you read this book, so if you are having performance or memory problems with your J2ME programs, this application is probably worth checking out. The esmertec Web site is www.esmertec.com.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 175
Java for Palm Connected Organizers
175
Chapter Summary In this chapter, we looked at how to run J2ME applications on the Palm. Now we can move away from the CLDC and look at the MIDP Early Access release.
67957_Wiley_Giguere_CH08x
10/17/2000 5:14 PM
Page 176
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 177
CHAPTER
9
The Mobile Information Device Profile (MIDP) Early Access Release
B
y itself, the Connected Limited Device Configuration (CLDC) is not enough of a platform on which to build applications. Although the CLDC comes with a library of classes that adds the basic features that applications require, those classes are unsupported and are meant to be used as examples only. The Mobile Information Device Profile (MIDP), on the other hand, is a complete and supported foundation for application development. In this chapter, we will look at the first MIDP implementation: the MIDP Early Access Release.
Overview At this writing, the MIDP had finished its public review—one of the last steps before being published as a formal specification. To coincide with the public review period, an early access version of the MIDP was released so that the development community could start to use the new application programming interfaces (APIs) defined by the MIDP and start porting applications. By the time you read this text, the early access release will undoubtedly have been replaced by a reference implementation of the final MIDP specification, so please check the Sun Microsystems Web site at http://java.sun.com/products/midp for details
177
67957_Wiley_Giguere_CH09x
178
10/17/2000 5:15 PM
Page 178
CHAPTER 9
about how to download the latest MIDP reference implementation. The information here is based solely on what is found in the early access release, so there could be differences between what is available in the reference implementation. If by some chance the reference implementation is not yet available, you can download the early access release from the Java Developer Connection at http://developer.java.sun.com. For brevity, we will often refer to the MIDP early access release as “the MIDP” throughout the remainder of this chapter. Please note that the early access release is based on version 0.9 of the MIDP specification, although at the time of writing the 0.95 specification was the most recent one available.
Installation Like the CLDC reference implementation, the MIDP is installed by extracting the files from the ZIP file that you downloaded from the Sun Web site. Versions for Windows and Solaris are available, but we will limit ourselves to describing the Windows version. The files are extracted directly into the installation directory of your choice, and no setup program is necessary. The ZIP file contains the following items: ■■
■■
■■
■■ ■■
An index.html file describing how to install the release and run the samples Binaries for the MIDP cellular telephone simulator and the preverifier (in the bin directory) Documentation on how to run the simulator and the samples, as well as a complete Javadoc for the classes included in the early access release (in the docs directory) The midp.jar file containing the MIDP classes (in the lib directory) Sample MIDlets that run in the cellular phone simulator (in the lib\ examples.jar file, the sources are found in the src\example directory)
The MIDP directory structure is simpler than the CLDC’s, because the early access release is a binary release that includes no source (except that of the samples).
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 179
The Mobile Information Device Profile (M I D P) Early Access Release
179
Note that the early access release deviates from the MIDP 0.9 and 0.95 specifications in a few minor ways. These deviations are listed in the index.html file accompanying the early access release.
Using the Cellular Phone Simulator Like the CLDC reference implementation, the MIDP early access release includes a simulator that enables you to run J2ME applications on your desktop computer. Unlike the CLDC simulator, the MIDP simulator is quite polished, as shown in Figure 9.1. The simulator emulates a cellular phone, which is one of the profile’s target devices.
Figure 9.1 The MIDP cellular phone simulator.
67957_Wiley_Giguere_CH09x
180
10/17/2000 5:15 PM
Page 180
CHAPTER 9
Running the Simulator You run the simulator by using the midp.exe executable in the bin directory. Use one of the following arguments to run a MIDlet: ■■ ■■
■■
■■
The name of a class specifies the name of the MIDlet class to run. -descriptor file specifies the path to an application descriptor (a text file ending in a .jad extension) that describes a MIDlet suite. The simulator will enable you to choose which MIDlet to run. -transient url appname specifies the URL of an application descriptor and the name of the MIDlet within it to run. The MIDlet name is a name listed in the descriptor, not the class name of the MIDlet. The name is actually optional. If this option is not specified, the simulator will enable you to choose which MIDlet to run. -autotest url appname is similar to –transient except that the application is run repeatedly until the simulator is shut down.
When searching for non-MIDP classes, the cellular phone simulator uses the CLASSPATH environment variable unless the –classpath path option is specified. The midp.jar file does not have to be in the classpath; rather, it is used when compiling applications, not when running them. To exit the simulator at any time when not in autotest mode, simply close the window. In autotest mode, you will have to interrupt the simulator by using Ctrl+Break at the console window. If you are running a specific MIDlet (you were not prompted by the simulator to choose an individual MIDlet from a suite), you can also press the hang up button (the red telephone icon on the right of the simulator).
Web Server Setup When downloading application descriptors from a Web server, the Web server must return a MIME type of text/vnd.sun.j2me.appdescriptor for files ending in .jad. How you define this mapping is specific to the Web server that you are using. For Apache Web servers, add an entry to the mime.types file, or else add the following command to the httpd.conf file: AddType text/vnd.sun.j2me.app-descriptor .jad
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 181
The Mobile Information Device Profile (M I D P) Early Access Release
181
Example Invocations A few simple examples demonstrate how to invoke the cellular phone simulator by using each method. Say that you have a MIDlet suite packaged as test.jar whose contents are as follows: /META-INF/MANIFEST /com/mycompany/Test1.class /com/mycompany/Test2.class /icons/Test1.png /icons/Test2.png
Accompanying this Java Archive (JAR) file is an application descriptor, test.jad, whose contents are as follows: MIDlet-Jar-URL: http://localhost/test.jar MIDlet-Jar-Size: 2304 MIDlet-Name: Test MIDlet-Version: 1.0 MIDlet-Vendor: mycompany.com MIDlet-Description: A simple test. MIDlet-1: Test1, /icons/Test1.png, com.mycompany.Test1 MIDlet-2: Test2, /icons/Test2.png, com.mycompany.Test2 MicroEdition-Profile: MIDP-1.0 MicroEdition-Configuration: CLDC-1.0
As you can see, the MIDlet suite has two MIDlets: Test1 and Test2. Assume that you have an Apache Web server installed on your machine such that the URL http://localhost/file maps to c:\apache\htdocs\ file. The Web server is up and running on the default port (port 80) and is configured to serve .jad files by using the correct MIME type. As a final step, place the test.jar and test.jad files in the c:\apache\htdocs directory. To run Test1 in the simulator without using the application descriptor or the Web server, use the following: midp -classpath c:\apache\htdocs\test.jar com.mycompany.Test1
The simulator loads the given class directly from the JAR file. To run either MIDlet by using the application descriptor but not the Web server, use the following:
67957_Wiley_Giguere_CH09x
182
10/17/2000 5:15 PM
Page 182
CHAPTER 9 midp -classpath c:\apache\htdocs\test.jar -descriptor c:\apache\htdocs\test.jad
The simulator uses the descriptor to build a list of MIDlets that it can run. To download and run Test2 from the Web server, use the following: midp -transient http://localhost/test.jad Test2
Omit the MIDlet name, and the simulator will build and present a list of MIDlets to run.
Running the Samples Just like the CLDC, the MIDP comes with a number of samples. The samples are packaged as a single MIDlet suite called examples.jar, which you will find in the lib directory. The simplest way to run the samples is to use the run.jad file that is found in the MIDP installation directory. Run this command from the bin directory: midp -classpath ..\lib\examples.jar -descriptor ..\run.jad
The simulator will list the MIDlets in the JAR. You can run any sample by simply scrolling to it (using the arrow buttons on the simulator or the arrow keys on your keyboard) and selecting it (using the circle button on the simulator or the Enter key on your keyboard). To run the samples in full color, set the SCREEN_DEPTH environment variable to 8 before invoking the simulator: set SCREEN_DEPTH=8 midp -classpath ..\lib\examples.jar -descriptor ..\run.jad
Use a screen depth of 8 for 256 colors, 4 for 16 colors, 2 for four colors, or 1 for black and white. For other environment variables that you can set, refer to the file docs\midp-env.html. The samples are self-explanatory. The Sampler sample, which demonstrates simple drawing commands, is shown in Figure 9.2.
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 183
The Mobile Information Device Profile (M I D P) Early Access Release
183
Figure 9.2 The Sampler sample.
Compiling and Preparing Classes You can compile a MIDlet by using the javac command as follows: javac -g:none -bootclasspath %MIDP_HOME%\lib\midp.jar -classpath %MIDP_CLASSPATH% -d %MIDP_TMP_DIR% *.java
Like we did with the CLDC, we defined a MIDP_HOME environment variable and set it to the root of our MIDP installation. We also defined
67957_Wiley_Giguere_CH09x
184
10/17/2000 5:15 PM
Page 184
CHAPTER 9
MIDP_OUTPUT_DIR, MIDP_CLASSPATH, and MIDP_TMP_DIR environment variables. Compiled classes must be run through the preverifier, just like we did with the CLDC. The syntax is the same, except that the class path includes the MIDP classes in place of the CLDC classes: %MIDP_HOME%\bin\preverify -d %MIDP_OUTPUT_DIR% -classpath %MIDP_CLASSPATH%;%MIDP_HOME%\lib\classes %MIDP_TMP_DIR%
Before running the preverifier, however, you should use the jar command to extract the contents of the midp.jar file into the lib\ classes directory: cd %MIDP_HOME%\lib mkdir classes cd classes jar xf ..\midp.jar
If you include the midp.jar file directly into the class path, the preverifier will not find the MIDP classes. Now you can test your application by using the simulator. Once you have tested your MIDlet, you will need to package it into a JAR file along with any other MIDlets in the suite. Do not forget to include a manifest that has the required attributes. You should also define an application descriptor for the suite.
The HelloMIDlet Application The MIDP early access release includes a skeleton MIDlet called HelloMIDlet that you can use as a starting point for your own MIDlets. This application is already included in the examples.jar file, so you can run it like any of the other samples: midp -classpath ..\lib\examples.jar HelloMIDlet
The HelloMIDlet application uses a TextBox to display a string of text and then waits for the user to invoke the exit command. Refer to Figure 9.3.
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 185
The Mobile Information Device Profile (M I D P) Early Access Release
185
Figure 9.3 Running the HelloMIDlet application.
While this MIDlet is pretty basic, this application is certainly more complex than the HelloWorld application that we defined previously with the CLDC: // HelloMIDlet.java — from the MIDP early access examples import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HelloMIDlet extends MIDlet implements CommandListener { private Command exitCommand;
67957_Wiley_Giguere_CH09x
186
10/17/2000 5:15 PM
Page 186
CHAPTER 9 private Display display; public HelloMIDlet() { display = Display.getDisplay( this ); exitCommand = new Command( "Exit", Command.SCREEN, 2 ); } public void startApp() { TextBox t = new TextBox( "Hello MIDlet", "Test string", 256, 0 ); t.addCommand( exitCommand ); t.setListener( this ); display.setCurrent( t ); } public void pauseApp() { } public void destroyApp( boolean unconditional ) { } public void commandAction( Command c, Displayable s ) { if( c == exitCommand ){ destroyApp( false ); notifyDestroyed(); } } }
When the MIDlet is created, its constructor grabs a reference to a Display object and creates a Command object. The Display object is used later to set the current screen and is valid until the MIDlet is destroyed. The Command object defines an exit command that will be later associated with a screen. When the MIDlet is started, it creates a TextBox screen, associates the exit command with it, and makes the screen current. At this point, the high-level user interface classes takes over and displays the text on the screen. Notice how the MIDlet also implements the CommandListener interface and is registered as a listener with the TextBox. Any commands that are trigged by the user thereby invoke the commandAction method, which in this case just checks to determine whether the exit command was the source and destroys the MIDlet if so. When the application is destroying itself, it notifies the device by calling notifyDestroyed.
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 187
The Mobile Information Device Profile (M I D P) Early Access Release
187
Can you still print text by using System.out and System.err? The answer is yes, and the text will appear on the console as you would expect when the application is run on the simulator. On a real device, of course, the text will likely go elsewhere. Again, only use these output streams for tracing and debugging purposes.
The Tic-Tac-Toe Example We can easily adapt the tic-tac-toe game that we developed in the previous chapter, transforming it from a spotlet to a MIDlet. Instead of having the TicTacToe class draw the user interface and interact with the user, however, we are going to move most of its functionality into a separate TicTacToeUI class. TicTacToe is then left as a simple MIDlet that follows the basic outline of the HelloMIDlet application: public class TicTacToe extends MIDlet implements CommandListener { .... }
The complete source for these classes is also listed in Appendix A and is available on the accompanying CD-ROM, along with the compiled version of the game. The compiled version is actually packaged as a MIDlet suite, and when run with the cellular phone simulator, you will see the tic-tac-toe game listed as shown in Figure 9.4. Select the game and then a few cells, and you will see something similar to Figure 9.5. Note how real circles are drawn in this version. The MIDP Graphics calls include a drawArc method for drawing full or partial circles and ellipses. The only real difference between TicTacToe and HelloMIDlet is that the former creates instances of TicTacToeModel, TicTacToePlayer, and TicTacToeUI and registers the latter two as listeners for the model. Because we need to draw directly on the device’s screen, TicTacToeUI extends the Canvas class as well as implements TicTacToeModelListener: public class TicTacToeUI extends Canvas implements TicTacToeModelListener { .... }
67957_Wiley_Giguere_CH09x
188
10/17/2000 5:15 PM
Page 188
CHAPTER 9
Figure 9.4 Accessing TicTacToe from the MIDlet suite.
Just as we did with the Palm version, most of the drawing logic is encapsulated in the gameUpdated method. In fact, the code in both versions is nearly identical, with most of the changes due to the differences in how painting is done (in response to events for MIDP versus completely application-managed events for the Palm) and how user input is obtained. The MIDP version of tic-tac-toe uses the keypad for cell selection. In other words, to select the top-left corner cell, you press 1; to select the bottom-left corner cell, you press 7; and so on. The input is processed by the keyPressed method:
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 189
The Mobile Information Device Profile (M I D P) Early Access Release
Figure 9.5 Running the MIDP TicTacToe.
public void keyPressed( int keyCode ){ if( model == null || !model.isGameStarted() ) return; int index; for( index = 0; index < keypad.length; ++index ){ if( keypad[index] == keyCode ) break; } if( index < keypad.length ){ model.setCellState( index, TicTacToeModel.PLAYER_1 ); } }
189
67957_Wiley_Giguere_CH09x
190
10/17/2000 5:15 PM
Page 190
CHAPTER 9
Another difference between the two versions of tic-tac-toe is how the winner is announced. The MIDP version uses an instance of the Alert class: Alert alert = new Alert( "Game Over" ); alert.appendString( msg ); // msg is the string to display alert.setTime( Alert.FOREVER ); Display.getDisplay( midlet ).setCurrent( alert, this );
The call to setCurrent makes the alert the current screen and hides the game board, as shown in Figure 9.6. When the alert is dismissed, it makes the game board the current screen again. When the game board reappears, its showNotify method is invoked in order to start a new game:
Figure 9.6 The tic-tac-toe alert.
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 191
The Mobile Information Device Profile (M I D P) Early Access Release
191
protected void showNotify(){ if( model != null && !model.isGameStarted() ){ model.newGame(); repaint(); } }
The user can exit the game at any time by pressing the button marked Exit.
Chapter Summary In this chapter, we examined how to compile and run J2ME applications with the MIDP Early Access Release. Now, we move on to running J2ME applications on Motorola devices.
67957_Wiley_Giguere_CH09x
10/17/2000 5:15 PM
Page 192
67957_Wiley_Giguere_CH10x
10/17/2000 5:16 PM
Page 193
10
CHAPTER
Java for Motorola Devices
A
s the specification lead for the Mobile Information Device Profile (MIDP), Motorola has devoted a large number of resources to implementing J2ME on its devices. At the JavaOne conference in the early summer of 2000, Motorola demonstrated devices running J2ME and committed to Java-enable all their cellular telephone models by the middle of 2002. In fact, the first MIDP-enabled phone from any vendor, the Motorola i3000, is scheduled to ship in December 2000, shortly after this book is published. In this chapter, we will look at Motorola’s implementation of J2ME using the Motorola J2ME SDK, a beta of which you will find on the CD-ROM accompanying this book. All of the information on this chapter is based on Developer Drop #5 of the Motorola J2ME SDK, which is the version that is available on the CD-ROM. Be sure to check Motorola’s iDEN developer Web site at www.idendev.com for the latest version of the SDK.
193
67957_Wiley_Giguere_CH10x
194
10/17/2000 5:16 PM
Page 194
C HAPTE R 10
The Motorola J2ME SDK Since cellular telephones are familiar to everyone, we can move right along to installing and using the Motorola J2ME SDK, which we will refer to simply as “the SDK” for the remainder of this chapter.
Installing the SDK The SDK is a ZIP file, so to install it just extract the contents on a Windows NT or Windows 98 machine. Be sure to install it to C:\MotoSDK, as some parts of the SDK use this hard-coded path. We will refer to this directory as the installation directory. You’ll also need to install the Java 2 SDK, version 1.2.2 or higher, as parts of the Motorola SDK are written in Java and require J2SE to run. The Motorola SDK does not include an integrated development environment (IDE). You can, however, purchase and use Motorola’s own CodeWarrior Pro 6.0 product, available from its Metrowerks subsidiary. Refer to www.metrowerks.com for details. CodeWarrior Pro is a fullfeatured IDE that can target multiple languages, including Java. The Motorola SDK adds the capability to compile and debug J2ME programs to CodeWarrior, making it the preferred development tool for Motorola devices. However, the SDK can be used with or without CodeWarrior, and in this chapter we use it without an IDE. After installing the SDK, take a few moments to read through the user’s guide, available in PDF format in the installation directory.
Using the SDK The SDK includes everything you need to create MIDP-based J2ME applications for Motorola devices. It includes an emulator that simulates the J2ME environment in various cellular telephones as well as all the files required to build MIDlets. The only thing you need to supply is JDK 1.2.2. The SDK consists of the following directories: docs. Javadoc for both the CLDC and the MIDP classes lib. The compiled classes for building applications lib.tools. Classes for the Motorola-specific tools
67957_Wiley_Giguere_CH10x
10/17/2000 5:16 PM
Page 195
Java for Motorola Devices
195
libmidlets. The compiled versions of the Motorola MIDP samples preverifier. The Motorola version of the preverification tool src. Source code for the samples vm. Dynamic link libraries for the KVM, for use by the emulator As well, you will find a number of command (batch) files in the installation directory for running and configuring the emulator, which we will describe shortly.
Using the Emulator Just like the Early Access MIDP reference implementation we discussed in the last chapter, the Motorola J2ME SDK includes a cellular telephone emulator for running J2ME applications on your desktop. There are different configurations of the emulator available, such as the generic emulator shown in Figure 10.1 or the iDEN emulator shown in Figure 10.2. You can also define your own configurations using the runConfig.bat file to invoke the configuration tool shown in Figure 10.3—refer to the user’s guide for instructions on how to configure new emulators. You can change the network packet size, the amount of memory available to the VM, and other features that can vary from device to device. To run an emulator, simply invoke the appropriate command file: runEmul.bat to run the generic emulator or one of runMotoi1000.bat, runMotoiDEN.bat, runStarTac.bat to run emulators for specific Motorola cellular telephones. These command files must be invoked from the SDK installation directory, and each takes a fully qualified Java class name as its single argument. For example, to run the PaddleBall sample use this command: runMotoiDEN com.mot.j2me.midlets.paddleball.PaddleBall
The class name must refer to a compiled MIDlet found in either the C:\MotoSDK\lib or C:\MotoSDK\libmidlets directories. You can modify the command file to include your own directories if you would rather not copy your own files into the SDK directories. If no class name is specified, the command file defaults to running the com.mot.j2me.midlets.bounce.Bounce sample.
67957_Wiley_Giguere_CH10x
196
10/17/2000 5:16 PM
Page 196
C HAPTE R 10
Figure 10.1 The generic emulator.
Note that at this writing the emulator does not include any kind of application manager and is limited to running a single MIDlet at a time.
Running the Samples The SDK includes a number of precompiled sample MIDlets, including the PaddleBall and Bounce samples referred to in the previous section.
67957_Wiley_Giguere_CH10x
10/17/2000 5:16 PM
Page 197
Java for Motorola Devices
197
Figure 10.2 The iDEN emulator.
Developer Drop #5 of the SDK also includes a command file called drop05exe.bat for running all the samples, one at a time. The name of this file will surely change in future versions of the SDK, but look for a file with a similar name and run through all the samples just to get a feel for the emulator and what MIDlets can do. All the samples are described in detail in the user’s guide.
67957_Wiley_Giguere_CH10x
198
10/17/2000 5:16 PM
Page 198
C HAPTE R 10
Figure 10.3 The emulator configuration tool.
Compiling and Preparing Classes Classes are compiled and prepared using the same techniques described in the last chapter. Use the preverifier included with the SDK and place the C:\MotoSDK\lib directory in the classpath for both javac and the preverifier. No other changes to the procedure are required.
The Tic-Tac-Toe Example No substantial changes are required to run the tic-tac-toe game we developed in the last chapter with the Motorola emulator. Minor changes are required to deal with differences in the MIDP specifications
67957_Wiley_Giguere_CH10x
10/17/2000 5:16 PM
Page 199
Java for Motorola Devices
199
Figure 10.4 Tic-tac-toe on the Motorola emulator.
each supports: The Motorola SDK supports the MIDP 0.95 specification, while the Early Access release discussed in the last chapter supports MIDP 0.9. Apart from these few changes, however, the tic-tac-toe example runs perfectly with the Motorola SDK, as shown in Figure 10.4.
67957_Wiley_Giguere_CH10x
200
10/17/2000 5:16 PM
Page 200
C HAPTE R 10
Chapter Summary In this chapter, we examined how to use the Motorola J2ME SDK to run MIDlets. In the next chapter we discuss running J2ME applications on a different set of wireless devices, the BlackBerry Wireless Handhelds.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 201
11
CHAPTER
Java for BlackBerry Wireless Handhelds
O
ne of the most popular sets of wireless devices in North America is the Research In Motion (RIM) family of BlackBerry wireless handhelds. RIM is one of the first companies other than Sun Microsystems to release a J2ME implementation. In this chapter, we will take a look at RIM’s JDE for BlackBerry, which is an in-progress MIDP implementation that includes an integrated compiler, debugger and emulator. This complete tool set moves J2ME application development to the level that you have come to expect from the J2SE.
All of the information in this chapter is based on the early-access version of the BlackBerry JDE, which is available on the accompanying CD-ROM. The JDE is quite polished considering that it is a preliminary release, but be sure to check the RIM development Web site at http:// developer.rim.net for an updated version of the JDE.
A BlackBerry Primer RIM has been developing wireless devices for a number of years. Its BlackBerry devices—two-way interactive pagers—are sold by a number of retailers and network operators in Canada and the United States. Although the devices themselves might be of only minor interest to
201
67957_Wiley_Giguere_CH11x
202
10/17/2000 5:17 PM
Page 202
C HAPTE R 11
readers outside the United States and Canada, the BlackBerry JDE is worth exploring by anyone who is doing CLDC- or MIDP-based development because of its integrated environment. Before examining the JDE, however, let’s take a brief look at the technology that drives a BlackBerry device.
A User’s Perspective The BlackBerry wireless handheld family includes several different models. Two of the models, the 950 and the 957, were illustrated in Figures 1.4 and 1.5 back in the first chapter of this book. Each model includes a small but complete QWERTY-style keyboard for entering text as well as a thumb-operated trackwheel for positioning the cursor and selecting. There are two form factors available: a Palm-like form factor with a large screen (shown in Figure 1.5) and a pager-like form factor with a smaller screen (shown in Figure 1.4). The small screen displays six or eight lines of text, while the large screen displays 16 or 20 lines of text. The screen is not touch-sensitive, and all input is done via the keyboard or trackwheel. The trackwheel can also be pressed in order to act as a push button. RIM’s devices are lightweight. The smaller form factor weighs in at less than five ounces (including the battery), while the larger form factor is just a tiny bit heavier (and of course includes a built-in radio modem). The devices work on a single AA battery or on a built-in rechargeable battery, depending on the model. A docking cradle enables the devices to connect to a desktop computer for application installation, backups, and other tasks that require a fast network connection. All RIM devices use either the Mobitex or DataTAC networks for wireless data communication. Unlike the Palm VII, which currently uses Mobitex, the wireless modem in a RIM device is always on (there is no antenna to raise). This feature makes it possible to send and receive e-mail and other notifications at any time. E-mail, of course, has been the primary application for the devices so far, and the keyboard makes sending text a much more pleasant task than using a cellular telephone keypad. Also, unlike the Palm VII, the RIM solution does not require you to obtain a new e-mail address. It integrates with your existing corporate e-mail server or with existing Internet (POP3 or IMAP) mailboxes.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 203
Java for BlackBerr y Wireless Handhelds
203
A Developer’s Perspective Although the RIM devices were originally referred to as “interactive pagers,” they are capable of doing more than just sending and receiving messages. Third-party developers can use the RIM software-development kit to build their own applications in C++, and now in Java with the BlackBerry JDE. All current RIM devices have a 32-bit Intel 386 processor at their core, although there is speculation that this specification might change in newer devices. Each device includes at least 2MB of Flash memory and at least 300K of RAM. A RIM device has its own operating system and includes APIs that are necessary for accessing the Flash memory and for sending and receiving packets on the radio, in addition to those that are necessary for displaying information and interacting with the user. Up to 31 applications can run simultaneously by using co-operative multi-tasking. C++ applications are developed by using Microsoft’s Developer Studio tool set. The applications are compiled as Windows dynamic link libraries (DLLs) that are downloaded to the device via the cradle. The RIM SDK also includes a simulator that enables you to test your programs without installing them on a real device. Java applications are developed with the BlackBerry JDE, which we will discuss next.
The BlackBerry JDE With a basic understanding of the BlackBerry platform, we can now explore the BlackBerry JDE.
Installing the JDE To install the JDE, simply run the setup.exe program found on the CD-ROM in the RIM folder. You will need a machine that is running Windows 98 or Windows NT in order to use the JDE. The JDE installs a copy of the J2SE 1.3 SDK if you do not already have one on the
67957_Wiley_Giguere_CH11x
204
10/17/2000 5:17 PM
Page 204
C HAPTE R 11
machine. The SDK is used to run the Java-based integrated development environment (IDE) and to compile Java source files. The installation also includes all of the necessary CLDC and MIDP files for building J2ME-based applications that run on RIM devices. Throughout this chapter, we will assume that the JDE is installed in the directory c:\RIMJavaSDK and will refer to that directory as the JDE directory. Once you have installed the JDE, open the index.html file in the JDE directory with your favorite Web browser. Here, you will find links to important information about the JDE and related RIM and Java technologies, as well as a decent user guide for the JDE in Adobe PDF format.
Starting the IDE The heart of the RIM JDE is its IDE. You can run the IDE from your Start menu or directly from the JDE directory by using the following command: java -jar ide.jar
Again, the IDE requires J2SE 1.3 or higher and will refuse to start if it is run with J2SE 1.2. After the initial splash screen, you will be presented with the window shown in Figure 11.1. This window is the IDE, and it should look familiar to anyone who has done any programming with IDEs such as Microsoft’s Developer Studio. The main window is split into a number of configurable view windows. The initial views include a workspace view in the upper-left corner, a source view in the upper-right corner, and an output view in the bottom half.
Using the IDE The IDE organizes things in a fairly conventional manner. Projects define individual applications or code libraries. (A library defines a set of classes that are shared by two or more applications but is not an application in and of itself.) Projects are grouped together to form a workspace and are shown in the workspace view. Only a single workspace is open at a time. You can share projects among workspaces, however. Project and workspace information is stored in simple text files with the extension .jdw for workspaces and .jdp for projects.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 205
Java for BlackBerr y Wireless Handhelds
205
Figure 11.1 The BlackBerry IDE.
All Java source files must be part of a project. The project can also contain bitmap images in .GIF format, from which the IDE generates a Java class that can fetch the bitmaps at run time. Other file types are ignored. You compile a project by using the Build command either from the Build menu or by right-clicking the project and selecting the appropriate item from the pop-up menu. You can also use the pop-up menu to assign project dependencies. Applications can only depend on libraries, although libraries can depend on other libraries. When a project is built, any projects that it depends on are built first.
67957_Wiley_Giguere_CH11x
206
10/17/2000 5:17 PM
Page 206
C HAPTE R 11
When an error occurs during compilation, the error messages appear in the output window. You can press F4 or use the Next Error item in the Edit menu to move to each line in the source that generated an error, which makes it fairly simple to fix the errors. The IDE also has the capability to generate a makefile that you can use to build all of the projects in the workspace. This feature is useful when projects need to be built in batch mode. There is no need to invoke the IDE and send it keystrokes in order to simulate user input. Editing a Java class is simply a matter of double-clicking the name of the source file in the workspace view. An editor view will appear, showing you the source to the class in a text field and providing you with basic text-editing capabilities. You can also edit the source code outside the IDE by using your favorite text editor. The IDE detects that you have changed the file the next time it builds the project. You need to use the built-in editor for one thing, however: debugging.
Running and Debugging Code Once you have built an application, you can run it directly from within the IDE by using the RIM simulator. Press F5 or use the Go command in the Debug menu. (Any out-of-date projects are automatically rebuilt before any application is run.) The IDE includes an integrated sourcelevel debugger that works in conjunction with the simulator to help you easily find and correct program bugs. We will discuss the simulator in some detail in the next section, so for now, we will just concentrate on the debugging.
MAN Conflicts The simulator simulates a Mobitex-based device. Each Mobitex device has a unique number called a MAN that identifies it. The simulator uses a MAN of 15000000 by default. If two or more simulators try to use the same MAN, you will receive an error dialog upon startup. Sometimes this situation happens even when only one simulator is running because a previous instance did not shut down properly and left a .man file in the c:\RIMJavaSDK directory. You can usually ignore these errors and simply dismiss the dialog.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 207
Java for BlackBerr y Wireless Handhelds
207
The JDE debugger has all of the features that you would expect. Not only can you set breakpoints and trace in and out of code, but you can also view local variables, see the call stack, set watchpoints, and view memory statistics. These features are all available from the View menu. To set a breakpoint, open a source file in the IDE and move the cursor to the appropriate line of code. Press F9 or select the Break at Cursor command from the Debug menu. You will see a red circle appear in the left margin of the line. Repeat the command to remove the breakpoint. The debugger stops whenever it encounters a breakpoint, enabling you to observe the state of the application, change the values of local variables, examine the call stack, and so on. Once execution has been stopped, you can step through the code a line at a time or simply resume execution until the next breakpoint—or some other important event—occurs. Use the preferences dialog shown in Figure 11.2, which is available by selecting the Preferences command from the Edit menu, to control whether or not the debugger stops whenever an exception is thrown. This dialog is handy for tracking obscure bugs, but your application will likely break into the debugger many times before the offending code is reached.
Figure 11.2 Setting debugger preferences.
67957_Wiley_Giguere_CH11x
208
10/17/2000 5:17 PM
Page 208
C HAPTE R 11
Using the Simulator The RIM simulator enables you to run your applications on the desktop without downloading them to an actual device. The integrated development environment starts the simulator automatically (unless configured otherwise). By default, the simulator behaves like a 957 model with the large display (as shown in Figure 11.3). You can make it simulate a 950 model by opening the preferences dialog shown in Figure 11.4 and changing the command line to substitute OsPgrMb.dll for OsHhMb.dll. The smaller simulator is shown in Figure 11.5. You can use either model, and you should test your applications by using both form factors. You can also configure other aspects of the simulator
Figure 11.3 Simulating a 957.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 209
Java for BlackBerr y Wireless Handhelds
209
Figure 11.4 Changing the simulator preferences.
Figure 11.5 Simulating a 950.
from this dialog by using the command-line options described in the user guide. When you first run the simulator, you will see a set of icons referred to as a ribbon. These icons represent the applications that you can run
67957_Wiley_Giguere_CH11x
210
10/17/2000 5:17 PM
Page 210
C HAPTE R 11
directly. On an actual device, you would scroll through the ribbon by moving the trackwheel with your thumb to select a particular application, which you would then start by pressing the thumbwheel. On the simulator, you move the trackwheel by using the up and down cursor keys or the mouse, either by using your mouse’s own wheel (if it has one) or by clicking and dragging the on-screen trackwheel (which is tricky to do, so use the cursor keys instead). You can press the trackwheel by pressing either the left or right cursor keys or by right-clicking the trackwheel. Note that the Enter key can often (but not always) be used as a shortcut to pressing the trackwheel.
Navigating with the Cursor Keys If you use the cursor keys to navigate the ribbon, remember that the up and down keys scroll through the items in the ribbon, while the left or right keys start the selected application. Confusing these operations is easy because the ribbon uses a horizontal layout. Your first inclination is to use the left and right keys. If you accidentally start an application that you did not mean to start, you can generally return to the ribbon by pressing the left or right cursor key to display the program’s menu. Then, you can use the up and down cursor keys to navigate to the menu’s Close item and press the left or right cursor key again. On an actual device, the interaction with the trackwheel is actually quite intuitive. The trackwheel simulation is what makes things awkward.
Any time that text input is required in the simulator, just type the characters with your regular keyboard. You can also use the mouse to press the individual keys on the on-screen keyboard. If the 957 is being simulated, your keyboard’s Esc key maps directly to the device’s own escape button, which is located just below the trackwheel. The simulator can even run applications that require wireless network connectivity. Because the simulator does not have a radio modem, it simulates wireless communication by writing data packets to the file system. This feature enables two instances of the simulator running on the same machine to communicate with each other. The simulator can even be configured to drop packets on occasion in order to better emulate real-world radio coverage. To stop the simulator, press its Close icon or use the Stop Simulator command in the IDE’s Debug menu.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 211
Java for BlackBerr y Wireless Handhelds
211
Running the Samples The BlackBerry JDE includes a number of sample applications in the Demos workspace that is loaded the first time you start the IDE. With the Demos workspace loaded, press the F5 key to build the samples (you will see the individual commands appear in the output view) and then run the simulator. The simulator will look like Figure 11.3. Only one of the samples, the JavaLogo application, is available directly from the ribbon. You can access the others by selecting and running the Options application and selecting the Java item from the list of options, as shown in Figure 11.6. Press the thumbwheel (or hit Enter) to launch the Java application manager and to see the list of available Java applications, as
Figure 11.6 Selecting the Java option.
67957_Wiley_Giguere_CH11x
212
10/17/2000 5:17 PM
Page 212
C HAPTE R 11
Figure 11.7 The Java application manager.
shown in Figure 11.7. You can run any of these samples by pressing the Enter key or by pressing the trackwheel and selecting the Run menu item. You can return to the application manager by pressing the trackwheel (or the left or right cursor key) and selecting the Close menu item. Most of the samples demonstrate the user interface capabilities that are available with RIM’s Java environment (described in the user guide). The Hello World sample includes a breakpoint at the start of the application, so if you start it, the IDE will activate itself and will enable you to step through the code. This point is a good place to start exploring the built-in debugger.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 213
Java for BlackBerr y Wireless Handhelds
213
RIM’s J2ME Implementation With the JDE installed and tested, we can now explore RIM’s J2ME implementation.
Overview RIM was an active participant in the definition of the MIDP, and as such, the RIM Java environment supports the MIDP. At least, it will support the MIDP in the future; however, right now the early-access version only supports the basic CLDC classes plus the MIDP classes for record management. It adds to this support a communications driver for direct radio packet access and its own set of device-specific classes. Full MIDP support is promised and might be available by the time you read this book. For now, RIM applications are built by using RIM-specific user interface classes and utility classes. Not all of these classes will be supported in the final release, so applications that you develop now with the early access version will need to be ported when an MIDPbased version is available. Keep this fact in mind when you write your code. Javadoc for all of the classes included in the JDE is found in the c:\RIMJavaSDK\docs directory. Although the RIM Java environment is CLDC-compliant, it does not include the KVM. It includes a custom-coded Java virtual machine (VM) that was written and optimized specifically for RIM devices, which we will refer to as the RVM. Until the MIDP is fully supported, applications must be compiled and packaged by using RIM’s development tools (as discussed next).
A First Application We will start our exploration by building the standard Hello world application for the RVM. Because one of the samples is called HelloWorld, we will call our version HelloWorld2. Start the IDE and create a new workspace called Test, placing it in whichever directory you want. In the workspace view, right-click the Test.jdw file and create a new project called HelloWorld2. Right-click the new project and select the Properties item to display the project’s properties dialog.
67957_Wiley_Giguere_CH11x
214
10/17/2000 5:17 PM
Page 214
C HAPTE R 11
Figure 11.8 Setting the HelloWorld2 properties.
This dialog specifies whether the project is a library or an application and defines the title, version, and copyright information for the project (as well as the name of the class that is used for storing resources). Fill in this dialog as shown in Figure 11.8. After dismissing the dialog, rightclick the project again and mark it as active so that it can be run and debugged. Active projects are bold in the workspace view. Now you are ready to add some code. Right-click the HelloWorld2 project and create a new file called HelloWorld2.java. Double-click the file that you just created in order to bring up the text editor, and enter the following code just like we wrote in Chapter 7 (except for the name of the class): public class HelloWorld2 { public static void main( String[] args ) { System.out.println( "Hello, world!" ); // Wait for ten seconds try { Thread.sleep( 10000 ); } catch( InterruptedException e ){ } } }
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 215
Java for BlackBerr y Wireless Handhelds
215
Now, press F5 to build the project and launch the simulator. Start the application manager and then run the HelloWorld2 application. The program starts, but then the debugger comes to the foreground with an uncaught null pointer exception. Unfortunately, it looks like System. out is not defined in this version of the RIM JDE, so it looks like we will have to build a version that uses the RIM user interface classes. Before we do that, though, let’s install the HelloWorld2 application on the ribbon just to make it easier to start (going through the application manager every time is quite tedious). To place an application on the ribbon, you just need to define some application icons for it. An application icon is a monochrome .GIF file that contains a 16-by-16 image (for the 950’s form factor) or a 28-by-28 image (for the 957’s form factor). You should define both icons. For our purposes, we are just going to use the icons from the Java Logo sample application. From the workspace view, right-click the HelloWorld2 project and select the Add File command to open a file dialog. Navigate to the c:\RIMJavaSDK\Demos\Images directory and select the CUP_16.gif and CUP_28.gif files. After adding these files to the project, right-click each one and bring up its properties dialog, as shown in Figure 11.9. Check the appropriate choice to mark each image as an application icon, then rebuild the project. Run the application. You will now see two identical Java logos in the ribbon: one for our application and one for the original Java Logo sample. You should modify the icons, of course, but for testing purposes, you can easily distinguish the applications by their titles.
Figure 11.9 GIF properties.
67957_Wiley_Giguere_CH11x
216
10/17/2000 5:17 PM
Page 216
C HAPTE R 11
A Better Application Let’s modify HelloWorld2 so that it works as promised. We perform this task by making the application extend the net.rim.device. api.ui.UiApplication class as follows: // Display a "hello, world" message import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; public class HelloWorld2 extends UiApplication { // Called on entry to the application public static void main( String[] args ) { // Create the application HelloWorld2 app = new HelloWorld2(); // Loop forever, waiting for events app.enterEventDispatcher(); } // Called when the application is activated public void activate() { // Create our main application screen MainScreen screen = new MainScreen(); // Set its title screen.addTitle( new TitleField( "HelloWorld2" ) ); // Add our message screen.add( new LabelField( "Hello, world!" ) ); // Display it pushScreen( screen ); } }
Run the application, and you should see the screen shown in Figure 11.10. This situation is much better. There is no way to exit the application, however, other than by shutting down the simulator or breaking into it from the IDE. We can fix this problem easily enough by listening for events from the thumbwheel and exiting the application whenever the thumbwheel is pressed or rolled. // Display a "hello, world" message and quit // when the thumbwheel is used import net.rim.device.api.ui.*;
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 217
Java for BlackBerr y Wireless Handhelds
Figure 11.10 The HelloWorld2 application. import net.rim.device.api.ui.component.*; import net.rim.device.api.system.*; public class HelloWorld2 extends UiApplication implements ThumbListener { public static void main( String[] args ) { HelloWorld2 app = new HelloWorld2(); app.enterEventDispatcher(); } public void activate() { MainScreen screen = new MainScreen(); screen.addTitle( new TitleField( "HelloWorld2" ) );
217
67957_Wiley_Giguere_CH11x
218
10/17/2000 5:17 PM
Page 218
C HAPTE R 11 screen.add( new LabelField( "Hello, world!" ) ); screen.addThumbListener( this ); pushScreen( screen ); } // Clean things up and quit private void close() { popScreen(); System.exit( 0 ); } // Called when the thumbwheel is pressed public boolean thumbClick( int status, int time ) { close(); return true; } // Called when the thumbwheel is released public boolean thumbUnclick( int status, int time ) { return false; } // Called when the thumbwheel is rolled "up" public boolean thumbRollUp( int status, int time, int amount ) { close(); return true; } // Called when the thumbwheel is rolled "down" public boolean thumbRollDown( int status, int time, int amount ) { close(); return true; } }
Now that we have a working application, let’s look more closely at how an application is built and then look at the application programming model.
Building Applications by Hand You can build an application from the command line by using the same steps as the IDE. Instead of compiling the files individually with javac,
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 219
Java for BlackBerr y Wireless Handhelds
219
running them through a preverifier, and then packaging them together in a JAR file, you can use the rapc.exe command: rapc import=base.jar;os.jar;font.jar;i18n.jar;ui.jar;rms.jar properties=HelloWorld2Resources codename=HelloWorld2 HelloWorld2.java HelloWorld2Resources.java
The source files are compiled by using javac (you will need to have the J2SE 1.3 SDK installed and in your search path) and are then run through RIM’s own tools in order to produce three files: HelloWorld2. jar, HelloWorld2.cod, and HelloWorld2.debug. The JAR file contains all of the class files as well as the other two files but is not needed to run the application. The code for the application is stored in the HelloWorld2.cod file. A .cod file can be significantly smaller than the equivalent set of .class files, which is a big advantage to this process. Debugging information is stored separately in the HelloWorld2.debug file. To run the application, all you need to do is copy the .cod file to the simulator’s working directory or onto the device (an application loader is provided with the JDE for transferring .cod files to a real device). The IDE performs this task for you automatically. If you want to debug the application, you will also need to copy the .debug file. Note that if your application includes any images, you will still have to run the IDE at least once in order to generate the resources file.
The Application Model For now, RIM’s J2ME implementation defines its own application model and its own set of user interface classes. The user interface classes are similar to the Swing classes in J2SE. Application Entry One of the classes in an RIM application must extend either net.rim. device.api.system.Application or net.rim.device.api. ui.UiApplication. The former is only used for applications that do not display any user interface, so most applications extend the latter. The application class must define the usual public static void
67957_Wiley_Giguere_CH11x
220
10/17/2000 5:17 PM
Page 220
C HAPTE R 11
main method as the application entry point. The entry point is responsible for creating a single instance of the application class—the application object—and entering the event dispatcher. Event Dispatching Events are processed by calling the application object’s enterEventDispatcher method. This method never returns. The thread that calls it is known as the event dispatching thread (event thread for short). All event callbacks will occur on that thread. The application continues to run, waiting for and dispatching events until explicitly terminated by calling System.exit. Like Swing, the RIM user interface classes are not thread-safe. All operations involving user interface components must take place on the event thread. The application object defines invokeLater and invokeAndWait methods that are similar to Swing’s in order to run code on the event thread. You can call the static method Application.isEvent-DispatchThread to determine whether the current thread is the event thread. The JDK 1.1 event model is used to deliver events. To receive events, a class must implement a listener interface and register itself with the source of the events. Unlike AWT events, however, the event values are passed directly to the event listeners instead of being wrapped in an event object. Screens and Graphics User-interface components are placed on screens that are subclasses of net.rim.device.api.ui.Screen. A screen is roughly analogous to an AWT window. The application maintains a stack of screens with the topmost screen receiving input events. To make a screen visible, you push it onto the stack using the application object’s pushScreen method and later remove them using popScreen. Screens repaint themselves automatically. Applications normally extend a subclass of Screen called MainScreen. Other subclasses of Screen implement menus and pop-up dialogs. A screen is itself a subclass of Manager, which in turn is a subclass of Field. Manager and Field are the RIM analogs of AWT’s Container
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 221
Java for BlackBerr y Wireless Handhelds
221
and Component classes. All user interface components extend Field, and all containers—user interface classes that group or lay out other user interface components—extend the Manager class. Horizontal and vertical layout managers are provided, but you can easily define your own layout by overriding the subLayout method of any manager. Drawing normally occurs within the paint method of a field or manager. A rim.net.device.api.system.Graphics object is passed to the method. The Graphics object supports basic drawing primitives. The getGraphics method of the Manager class can also be used to obtain a Graphics object if drawing is required outside a paint method, but this technique is not recommended. Instead, invalidate an area of the screen and wait for a paint event. User-Interface Components RIM’s user interface classes define a rich set of components. There are components for displaying lists, read-only text, editable text, formatted text, and bitmaps. Pop-up menus (which are actually implemented as screens) are available, as are choice controls and push buttons. Their use is fairly straightforward (it is just a matter of creating them, initializing their settings, and adding them to the appropriate manager).
Network Communication RIM devices are, of course, network devices that operate on one of two different radio networks. Java programs can access the network directly in order to communicate with applications that are running on other devices or with servers that are running on a network gateway. Although low-level radio access is available (through the net.rim. device.api.system.Radio class), the preferred way to do network communication is by using a datagram connection obtained from the CLDC’s Generic Connection framework (although it is currently only available for the Mobitex network). One of the samples included with the JDE, ChatTest, demonstrates a simple chat application that can be used to send text messages directly from one device to another. You can even run it with a single instance of the simulator and send messages to yourself. Refer to the sample and to the Javadoc for the javax.microedition.io.Connector class for more details.
67957_Wiley_Giguere_CH11x
222
10/17/2000 5:17 PM
Page 222
C HAPTE R 11
The serial port can also be accessed directly by using the Generic Connection framework (for use when the device is in its cradle). Furthermore, when the JDE supports the full MIDP specification, the HTTP protocol will also be supported.
Miscellaneous Classes The JDE supports a number of other classes beyond those that are required for building user interfaces and doing network communication. These classes cover the following areas: Internationalization. Several of the J2SE classes dealing with locales, formatting, and resource bundles are included with the JDE (but as part of a RIM-specific package). Utilities. Generic routines for data-structure manipulation, CRC calculations, and so on RMS. The MIDP Record Management System (RMS) is implemented. BlackBerry-specific. Classes that are of interest only to applications that are running specifically on a BlackBerry device Without a doubt, there will be further additions to this list as the JDE approaches its final release.
The Tic-Tac-Toe Example We conclude this chapter by adapting our tic-tac-toe example to work with the BlackBerry JDE. This version is based on the MIDP version discussed in Chapter 9 and uses the BlackBerry-specific user interface classes because the MIDP user interface components are not available with the early access version of the JDE. When full MIDP support is available, of course, the MIDP version will work without requiring any changes. For the complete code listings, refer to Appendix A. Since the RIM version of the tic-tac-toe game already uses RIM-specific classes, we are also going to adapt it so that the user can use the thumbwheel to move to and select a particular cell in addition to selecting a cell by pressing the keys 0 to 9.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 223
Java for BlackBerr y Wireless Handhelds
223
The TicTacToe Class The RIM version of the TicTacToe class is quite simple. After constructing an instance of the class and entering the event loop, the instance’s activate method is called to indicate that the application has been activated. The activate method reads as follows: public void activate() { gameScreen = new TicTacToeUI( this ); model.addListener( gameScreen ); model.addListener( new TicTacToePlayer( TicTacToeModel.PLAYER_2 ) ); model.newGame(); pushScreen( gameScreen ); }
The TicTacToeUI Class All the work is done by the TicTacToeUI class, which extends RIM’s FullScreen class in order to paint over the entire screen. When TicTacToeUI is constructed, it first creates a popup menu containing two text items: menu = new Menu(); menu.add( new MenuStringField( "Select Cell", MENU_SELECT_CELL ) ); menu.add( new MenuStringField( "Close", MENU_CLOSE ) ); menu.addMenuListener( this );
By making MENU_SELECT_CELL the first item in the menu the user can quickly select a cell by pressing the thumbwheel twice. The menu is displayed when the thumbwheel is clicked the first time, using this code: public boolean thumbClick( int status, int time ){ application.pushScreen( menu ); return true; }
Once the menu is pushed onto the screen stack, all input is directed to it. If the user closes the menu without selecting anything the menuClosed method is called:
67957_Wiley_Giguere_CH11x
224
10/17/2000 5:17 PM
Page 224
C HAPTE R 11 public void menuClosed( Menu menu ){ application.popScreen(); }
If on the other hand an item is selected, the menuSelected method is called instead: public void menuSelected( Menu menu, Field field ){ application.popScreen(); switch( ((MenuStringField) field).getId() ){ case MENU_CLOSE: System.exit( 0 ); break; case MENU_SELECT_CELL: model.setCellState( selectedCell, TicTacToeModel.PLAYER_1 ); invalidate(); break; } }
It is always up to the application to formally dismiss a menu by popping it from the screen stack. To allow the user to move from cell to cell using the thumbwheel we need to mark a cell as being selectable. We do this simply by adding a selectable flag to the Cell class. When a specific cell is painted and its selectable flag is set we simply invert the cell’s contents. The actual movement from cell to cell is done by trapping the thumbRollDown and thumbRollUp events: public boolean thumbRollDown(int status, int time, int amount){ moveCell( 1 ); return true; } public boolean thumbRollUp( int status, int time, int amount ){ moveCell( -1 ); return true; }
The actual movement is done by the moveCell method, as follows: private void moveCell( int offset ){ cells[ selectableCell ].setSelectable( false ); selectableCell += offset; if( selectableCell >= numCells ){
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 225
Java for BlackBerr y Wireless Handhelds
225
selectableCell = 0; } else if( selectableCell < 0 ){ selectableCell = numCells - 1; } cells[ selectableCell ].setSelectable( true ); invalidate(); }
A few more minor changes are required to adapt the TicTacToeUI class for the RIM environment, so please refer to the source code in Appendix A for the details.
Chapter Summary In this chapter, we looked at the RIMJDE, a different implementation of J2ME for a unique class of wireless hand-held devices. In the next chapter, we will move away from J2ME and look at an open source alternative for Palm OS and Windows CE: Waba.
67957_Wiley_Giguere_CH11x
10/17/2000 5:17 PM
Page 226
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 227
12
CHAPTER
Waba: An Alternative to Java
B
efore Sun Microsystems released a version of Java that was capable of running on a small computing device such as a Palm Pilot, a small California company called Wabasoft Corporation (www.wabasoft.com) was working on solving the same problem. Wabasoft created a development system called Waba that enables you to write Java programs that run on the Palm and Windows CE operating systems while still having the capability to run on the J2SE platform. Waba is an open-source product that has gained enough of a following that it deserves mention in this book as one alternative to J2ME, especially because it came out before the J2ME reference implementations. Waba is fairly limited, however, so it may not be suitable for your needs. In this chapter, we will look at what Waba is and how to use it.
What Is Waba? Waba is an alternative to Java for small devices. At the heart of the Waba system is the Waba virtual machine (VM), which is a virtual machine that can read and execute a subset of Java bytecodes. Waba is not a Java runtime environment, nor does it claim to be. Waba does, however, enable you to use a familiar language and familiar development tools to write portable applications for Palm and Windows CE 227
67957_Wiley_Giguere_CH12x
228
10/17/2000 5:18 PM
Page 228
C HAPTE R 12
devices. Waba performs this function by providing three elements: a virtual machine, a set of runtime classes, and a set of bridge classes.
The Waba VM The Waba VM accepts a subset of Java bytecodes. Specifically, it accepts and can run all of the standard bytecodes defined by The Java Virtual Machine Specification (except those that deal with long integers, doubles, exceptions, or threads). The classfile format is similarly constrained. The Waba VM can read Java class files that do not contain references to long integers or double values, either as bytecodes or in the constant pool. Exception tables in the class files are silently ignored. To create a Waba application, you need to write Java code that does not use the long or double types, that does not create or otherwise depend on threads, that does not throw or catch exceptions, and that only uses classes you write or that are provided with the VM. Compile the code with a Java compiler as you normally would in order to generate class files that the Waba VM can read. The Waba VM is quite small— about 33K on Palm OS.
The Waba Run Time Class files and bytecodes are not enough by themselves to write programs, of course. You also need a runtime library. Waba defines a set of foundation classes for user interface creation, network connectivity, and general programming. The classes are all defined in the waba package. In fact, the base class in the Waba system is waba.lang. Object—all classes in the Waba runtime library extend it, not java. lang.Object. No class in the waba package extends or implements any class or interface in the java package. You might wonder about references to java.lang.Object, java. lang.String, and java.lang.StringBuffer that are automatically generated by a Java compiler when it generates a class file. String concatenation using the + operator, for example, implicitly creates String and StringBuffer objects. If the Waba run time does not include any of the core classes from the java.lang package, how can Waba run such a class file? What the Waba VM does is simple: Each time it sees a reference to java.lang.Object, java.lang.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 229
Waba: An Alternative to Java
229
String or java.lang.StringBuffer, it simply substitutes waba.lang.Object, waba.lang.String or waba.lang. StringBuffer, respectively. These Waba classes implement a subset of the functionality of their java.lang counterparts, specifically those methods that are called by compiler-generated implicit code. The Waba runtime library is also quite small—about 40K on Palm OS.
The Bridge Classes The final piece in the Waba puzzle is the set of bridge classes. The bridge classes enable you to run Waba applications on a desktop system by using J2SE. In effect, they reimplement the Waba run time by using J2SE APIs. This function enables you to write Waba programs that not only run on Palm OS or Windows CE but that also run wherever J2SE itself runs. Figures 12.1 and 12.2 illustrate how this process works. Waba programs that are run with the bridge classes can run as applets or as standalone applications. Waba application Waba foundation classes Waba VM Windows CE or Palm OS Figure 12.1 Running Waba applications without Java.
Waba application Waba bridge classes J2SE runtime J2SE VM Operating system Figure 12.2 Running Waba applications with Java.
67957_Wiley_Giguere_CH12x
230
10/17/2000 5:18 PM
Page 230
C HAPTE R 12
Besides providing applications with additional portability, the bridge classes make it easier to develop and test the applications. You can use your favorite development environment to create, build, and run your programs, only occasionally building and testing them for an actual device. Even then, you are likely to use an emulator to do most of your testing.
Using Waba Getting ready to use Waba is just a matter of navigating to the Wabasoft Web site and downloading and installing the appropriate files on your device and on your desktop. These files are also available on the CD-ROM accompanying this book.
Installation The first thing to do is install the appropriate Waba VM on your Palm or Windows CE device. Each VM is packaged in a ZIP file with installation instructions. For Palm devices, install the waba.pdb and waba.prc files and then tap on the Waba icon, as shown in Figure 12.3. For Windows CE devices, install the waba.exe and waba.wrp files in a directory on the device. After installing the VM, install the Waba software development kit (SDK), which is packaged as two separate ZIP files. Just unzip the files
Figure 12.3 The Waba VM icon on the Palm.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 231
Waba: An Alternative to Java
231
into a directory and put the bin directory in your system path and the classes directory in your classpath. The bin directory contains the two Waba tools, exegen and warp, while the classes directory contains the Waba bridge classes. If you are interested in looking through the source of the VM or building it yourself, it is available as a separate ZIP file and is distributed under the GNU Public License. This source can be installed along with the Waba SDK. Instructions for building the Waba VM are found on Wabasoft’s Web site.
Running the Samples The first thing to do is to build and run the samples from the SDK. You will need to have J2SE installed on your machine. From the command line, go to the examples directory. This directory contains seven Waba samples, each of which is in its own subdirectory. Each subdirectory includes a make.bat file for building the particular sample. For example, here is how to build the Controls sample: cd c:\wabasdk.10\examples\Controls make
After building a sample, you can run it on your desktop by using the bridge classes. Here is how you run the Controls sample as a Java application: set CLASSPATH=.;c:\wabasdk.10\classes;%CLASSPATH% java waba.applet.Applet Controls
The running application is shown in Figure 12.4. You can also run the sample as an applet by using the HTML file that is provided with each sample as a guide. Once the sample is built, you can also run it with the Waba VM. The make.bat file generates the appropriate files for both Palm OS and Windows CE. Assuming that you have installed the Waba VM on your Palm OS device, simply install the generated .prc and .pdb files. After you HotSync, you will see an icon for the sample. The Controls sample running on Palm OS is shown in Figure 12.5. For Windows CE, copy the .wrp and .lnk files onto the device. You might have to adjust the paths stored in the .lnk file (by default, it assumes that the waba.exe
67957_Wiley_Giguere_CH12x
232
10/17/2000 5:18 PM
Page 232
C HAPTE R 12
Figure 12.4 The Controls sample as a Java application.
Figure 12.5 The Controls sample running on Palm OS.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 233
Waba: An Alternative to Java
233
file is in \Program Files\waba\waba.exe and that the sample is named \Program Files\sample\sample.wrp).
Compiling and Running Classes If you look at any of the make.bat files that build a sample, you will see that the build process for a Waba program is quite simple. The first step is to use the usual javac command to compile the Java source code, ensuring of course that the bridge classes are in the classpath: javac *.java
The next step is to use warp.exe to package the class files into a warp file, which is similar to a Java Archive (JAR) file: warp c AppName *.class
Two files are created: AppName.wrp for Windows CE and AppName. pdb for Palm OS. (Note that if you are building a Palm application that you wish to distribute to others, you should obtain a creator ID for it and assign it to the .pdb file by using Warp’s /c option.) The final step is to generate executables by using exegen.exe: exegen AppName MainClassName AppName
The parameters of exegen specify the name of the output file, the name of the application’s main class, and the names of the .wrp files that contain the application classes. Two additional files are created: AppName.prc for Palm OS and AppName.lnk for Windows CE. Various options are available to control memory usage, the path in the .lnk file, and the bitmap to use as an icon on Palm OS (if no bitmap is specified, a default bitmap is used). You run the application just as we did with the samples.
The HelloWorld Application Once again, we define a simple HelloWorld class: import waba.ui.*; import waba.fx.*;
67957_Wiley_Giguere_CH12x
234
10/17/2000 5:18 PM
Page 234
C HAPTE R 12 public class HelloWorld extends MainWindow { public void onPaint( Graphics g ) { g.setColor( 0, 0, 0 ); g.drawText( "Hello, world!", 0, 0 ); } }
Build the program by using these commands, assuming that the path and classpath are set correctly: javac HelloWorld.java warp c HelloWorld HelloWorld.class exegen HelloWorld HelloWorld HelloWorld
After installing the appropriate files on your device or emulator, run the HelloWorld application. You should see something similar to Figure 12.6.
Figure 12.6 The HelloWorld application.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 235
Waba: An Alternative to Java
235
Debugging Not only do the bridge classes make it possible to run Waba programs with J2SE, they also make it easy to debug a Waba program. Just use any of your usual debugging techniques and tools, such as tracing program execution through calls to System.out. At runtime you can use the waba.sys.Vm.getPlatform method to determine if you’re running with the bridge classes or on an actual device—it returns “Java” only when running with the bridge classes.
The Waba Foundation Classes Although profiles add new classes to a configuration, the core Java classes are common to all implementations of J2ME. In Waba, however, this is not the case. Waba defines a completely different set of runtime classes.
Overview The Waba foundation classes are currently grouped into six packages: 1. waba.fx for drawing graphics and playing sounds 2. waba.io for accessing files and databases and making network or serial port connections 3. waba.lang for the core Java classes Object, String, and StringBuffer 4. waba.sys for basic system functionality 5. waba.ui for user interfaces 6. waba.util for useful utility classes (currently consisting of a scaled-down Vector look-alike) Let’s look at a few of these classes in more detail.
The Application Model A Waba application’s main class extends waba.fx.MainWindow in much the same way as an applet extends java.applet.Applet in
67957_Wiley_Giguere_CH12x
236
10/17/2000 5:18 PM
Page 236
C HAPTE R 12
J2SE. The main class overrides the onStart method in order to initialize itself, usually by adding controls that are to be displayed as part of the main window. When the Waba VM starts the application, it creates an instance of the main class and invokes the onStart method before entering its event loop. A Waba application keeps running until the application calls the main window’s exit method, after which the onExit method is called in order to give the application an opportunity to perform some cleanup. Note that on Palm OS, the application can be terminated at any time by the user switching to another application, so be prepared to handle exits at any time.
The User Interface Waba defines Control and Container classes that are analogs to AWT’s Component and Container classes. In other words, all user interface components extend Control, and all components that can contain other components extend Container. Drawing is done by overriding a control’s onPaint method, as shown in the HelloWorld example. A container will paint its children automatically, but there are no layout managers to place and resize child controls. When you create a control, you must specify its absolute position and size. A Graphics class provides the usual drawing primitives. Drawing can occur directly on the screen or to an off-screen image. Events are trapped by overriding the onEvent method, much like the original AWT. There are no listeners to register. Four basic event types are supported: key events, pen/mouse events, control events, and timer events—although facilities exist for posting user-defined events. Only a few basic user interface controls are supported, including push buttons, radio buttons, checkboxes, labels, and edit fields. Notably missing is some kind of list control, although a tab control is included, as is built-in support for popup dialogs or any kind of window other than the main window.
Input/Output (I/O) All I/O classes in Waba extend the Stream class, which provides basic functions for reading and writing data. Waba supports a File class for
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 237
Waba: An Alternative to Java
237
reading or writing to the file system, but it does not work on the Palm because there is no file system available. A Catalog class provides a simple record-oriented database that maps to a native database on the Palm and to a file on Windows CE. A SerialPort class enables a Waba program to access the serial port, and a Socket class enables it to make a network connection.
The Tic-Tac-Toe Example For one final time, let’s adapt the tic-tac-toe game, this time for use with Waba. We actually base this version on the original Palm version discussed in Chapter 8, because the user interface models are similar. Waba’s classes are more complex and feature-complete, however. We start with changes to the TicTacToeModel and TicTacToePlayer classes. These classes have to change a bit because Waba doesn’t support the java.util.Enumeration or java.util.Random classes. Waba’s vector class, waba.util.Vector, is also quite different than J2SE’s java.util.Vector. We simulate random number generation in the player class by getting the current time, so instead of coding the following: import java.util.Random; .... private Random generator = new Random(); .... int cell = ( generator.nextInt() % max );
We code this: import waba.sys.Time; .... Time t = new Time(); int cell = ( ( t.millis + t.second + t.minute ) % max );
This is an adequate solution because the generated values will vary depending on how quickly the user plays the game. As for the model, we need to rewrite the listener notification code to directly iterate over the vector of listeners instead of using an enumeration. Most of the changes occur in the TicTacToe class, which creates and manages the user interface. Since we can paint directly on the main
67957_Wiley_Giguere_CH12x
238
10/17/2000 5:18 PM
Page 238
C HAPTE R 12
window, there is no need for a separate TicTacToeUI class. Most of the differences are in the way events are handled, using the onEvent method of the main window: public void onEvent( Event e ){ if( e instanceof KeyEvent ){ keyPressed( ((KeyEvent) e).key ); } else if( e instanceof PenEvent ){ PenEvent pe = (PenEvent) e; if( pe.type == PenEvent.PEN_DOWN ){ if( model.isGameStarted() ){ penDown( pe.x, pe.y ); } else { model.newGame(); } } } }
This event method merely redirects calls to the penDown and keyPressed methods, which we’re reusing unchanged from the Palm version. Since Waba doesn’t provide any support for even the most rudimentary of dialogs, the tic-tac-toe game simply clears out and reverses an area of the screen and prints the message there. All of this is done in the onPaint method, as follows: public void onPaint( Graphics g ){ g.setColor( 0, 0, 0 ); drawGrid( g ); drawPlayers( g ); if( !model.isGameStarted() ){ g.fillRect( 10, 40, width-20, height-80 ); g.setColor( 255, 255, 255 ); g.drawText( winnerText, 15, 40 ); g.drawText( "Tap to start over", 15, 60 ); } }
The game restarts when the user taps the screen. The remainder of the code is almost completely unchanged when compared to the Palm version.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 239
Waba: An Alternative to Java
239
Chapter Summary Although Waba is not Java, it might be worth looking at as an alternative to J2ME. The fact that it is open source means that you can enhance it yourself or even port it yourself to another platform, which is certainly easier than porting a J2ME implementation. Check this book’s Web site for other alternatives, as well.
67957_Wiley_Giguere_CH12x
10/17/2000 5:18 PM
Page 240
67957_Wiley_Giguere_CH13x
10/17/2000 5:18 PM
Page 241
13
CHAPTER
Final Thoughts
W
e have come to the end of our explorations, so we will finish with some final thoughts on the J2ME.
Alternatives to J2ME For various reasons, J2ME might not meet your needs as a programming platform for small devices. Perhaps you need access to low-level, device-specific APIs that no J2ME implementation exposes. Or maybe J2ME is not available for all of the devices in which you are interested. Or perhaps there are serious performance problems that you cannot easily overcome. Listed here are some alternatives to J2ME. Create your own J2ME implementation. This task is not something to undertake lightly, but if you really want to use J2ME even if it does not currently meet all of your requirements, then consider creating your own implementation. You can perform this action by porting or adapting an existing implementation (such as the CLDC reference implementation) or by contracting with someone to design the implementation for you.
241
67957_Wiley_Giguere_CH13x
242
10/17/2000 5:18 PM
Page 242
C HAPTE R 13
Explore the possibility of using J2SE instead. If your device supports it, J2SE or an earlier conventional form of Java might be a better choice than J2ME. Some EPOC-based (EPOC is an operating system promoted by the Symbian consortium) devices, for example, include either a Java 1.1.4 or a Java 1.1.8 implementation (with support for Java 2 promised later). Use a hardware-based Java VM. Several companies are creating Java runtime environments that incorporate some kind of hardware-based execution engine for better performance. If you are building an embedded system, you might consider including such a runtime environment in your system. Switch to a different programming language. Like we mentioned in the introduction, Java might not be the best language for the job. You could move to a Java-like solution (such as Waba) or to a completely different language and development environment. Obviously, you are reading this book in order to understand J2ME in the hopes of using it in your own projects, so the ideal solution does not involve any of these alternatives. It makes sense to consider them, however, because J2ME is still an immature technology that has lots of room to develop.
Conclusion Where does J2ME go from here? Right now, its functionality is still being fleshed out. Specifications are being written, and implementations are being tested. Only a few early adopters are seriously using J2ME in its current forms, although you can expect that to change as more and more device manufacturers start to include Java VMs with their basic system software. Cellular telephones are a particularly interesting market for Java. Motorola is promising to deliver the first MIDP-enabled phone by the end of 2000, just after this book is published; you will be able to load applications wirelessly onto your cellular phone and keep them there for use even when you are outside your coverage area. And you (and cellular phone manufacturers) can rest easy knowing that the Java sandbox will protect your precious phone from malicious applications. We have just begun the process of moving Java back to the client. Maybe this time, client-side Java will fulfill its promises.
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 243
APPENDIX
A
Tic-Tac-Toe Source Code
T
his appendix lists the source code for the tic-tac-toe game that we developed in this book.
Common Code Much of the code in the tic-tac-toe game is shared, so we will list these classes first.
TicTacToeModel The most important class, defines the model for the game. We discussed this class at some length in Chapter 3: package com.ericgiguere.j2mebook.models; import java.util.Enumeration; import java.util.Vector; /** * Defines the model for the TicTacToe game. This class * holds all the state information for the game and * notifies any listeners of state changes. The class
243
67957_Wiley_Giguere_AppA
244
10/17/2000 5:18 PM
Page 244
APPENDIX A * is also responsible for determining if a someone * wins and which cells were used to win, or if * the game is tied. * * This model can be used to define any tic-tac-toe game * of size n, where 3 <= n <= 6. To win you have to fill * a complete row. A better game would be to reduce the * number of cells you have to fill in order to win. * As it stands this game isn’t too challenging, but it’s * here mainly for demonstration purposes! */ public class TicTacToeModel { /** * The initial state of a cell. */ public static final int NO_PLAYER = 10; /** * A cell owned by player 1. */ public static final int PLAYER_1 = 1; /** * A cell owned by player 2. */ public static final int PLAYER_2 = -1; /** * An error value. */ public static final int ERROR = 0; /** * Constructs a model for a tic-tac-toe game. */ public TicTacToeModel(){ } /** * Adds a listener to this model. The listener * is notified whenever changes occur. * * @param listener the listener to register.
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 245
Tic-Tac-Toe Source Code
245
*/ public void addListener( TicTacToeModelListener listener ){ if( listener == null ) return; listeners.addElement( listener ); if( gameStarted ){ listener.gameStarted( this ); } } /** * Calculates the indices of each row and stores the * information in the rowIndices array. */ private void calculateIndices(){ int numIndices = cellsPerRow * numTotals; if( rowIndices == null || rowIndices.length < numIndices ){ rowIndices = new int[ numIndices ]; } // Now initialize each set of indices. // horizontal indices.
Start with the
int i, j, k; int index = 0; for( i = 0; i < numCells; ++i ){ rowIndices[index++] = i; } // Then the vertical indices: 0, (n+1), 2*(n+1), etc. for( i = 0; i < cellsPerRow; ++i ){ for( j = 0, k = 0; j < cellsPerRow; ++j, k += cellsPerRow ){ rowIndices[index++] = i + k; } } // Finally the two diagonals for( i = 0; i < cellsPerRow; ++i ){ rowIndices[index++] = i * ( cellsPerRow + 1 ); } for( i = 1; i <= cellsPerRow; ++i ){ rowIndices[index++] = i * ( cellsPerRow - 1 ); } }
67957_Wiley_Giguere_AppA
246
10/17/2000 5:18 PM
Page 246
APPENDIX A /** * Calculates the totals of each row. */ private void calculateTotals(){ int index = 0; for( int i = 0; i < numTotals; ++i ){ int total = 0; for( int j = 0; j < cellsPerRow; ++j ){ total += cells[ rowIndices[index++] ]; } totals[i] = total; } } /** * Fills a byte array with the states of the cells. * * @param outStates the byte array. If the array is not long * enough, nothing happens and false
* is returned. * * @return true
if the states were copied into the * given array. */ public boolean fillCellStates( byte[] outStates ){ if( outStates == null || outStates.length < numCells ) return false; System.arraycopy( cells, 0, outStates, 0, numCells ); return true; } /** * Fills an int array with the row totals. * * @param rowTotals the int array. If the array is not long * enough, nothing happens and false
* is returned. * * @return true
if the totals were copied into the * given array. */ public boolean fillTotals( int[] rowTotals ){ if( rowTotals == null || rowTotals.length < numTotals ) return false; System.arraycopy( totals, 0, rowTotals, 0, numTotals ); return true; }
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 247
Tic-Tac-Toe Source Code /** * Returns the number of cells in this game. * * @return the number of cells. */ public int getCellCount(){ return numCells; } /** * Returns the state of a particular cell. * * @param index the cell index. * * @return the state of the cell, either NO_PLAYER, PLAYER_1 * or PLAYER_2. Errors return ERROR. */ public int getCellState( int index ){ if( index < 0 || index >= numCells ) return ERROR; return cells[index]; } /** * Returns the state of a particular cell. * * @param row the row index of the cell. * @param col the column index of the cell. * * @return the state of the cell, either NO_PLAYER, PLAYER_1 * or PLAYER_2. Errors return ERROR. */ public int getCellState( int row, int col ){ return getCellState( row * cellsPerRow + col ); } /** * Returns the states of all the cells. A new array * is created and returned to prevent cheating. * * @return an array of cell states. */ public byte[] getCellStates(){ byte[] arr = new byte[ numCells ]; fillCellStates( arr ); return arr; }
247
67957_Wiley_Giguere_AppA
248
10/17/2000 5:18 PM
Page 248
APPENDIX A /** * Returns the indices for the given row. * * @param index the row index. * @param out the array in which to store the indices. */ public boolean getRowIndices( int index, int[] out ){ if( index < 0 || index >= numTotals ) return false; System.arraycopy( rowIndices, index * cellsPerRow, out, 0, cellsPerRow ); return true; } /** * Returns the size of the game. * * @return the size of the game, the number of cells in * a single row. */ public int getSize(){ return cellsPerRow; } /** * Returns the totals for all the rows in the game. * A new array is created and returned to prevent cheating. * * @return an array of row totals. */ public int[] getTotals(){ int[] t = new int[ numTotals ]; fillTotals( t ); return t; } /** * Returns the winner of the game that just ended. * * @return the winner of the game, either NO_PLAYER, * PLAYER_1 or PLAYER_2. */ public int getWinner(){ for( int i = 0; i < numTotals; ++i ){ int total = totals[i]; if( total == player1Wins ){ return PLAYER_1; } else if( total == player2Wins ){
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 249
Tic-Tac-Toe Source Code
249
return PLAYER_2; } } return NO_PLAYER; } /** * Returns the cell indices of the winning row. * * @param out the array in which to store the indices. * The array must be large enough, otherwise * an error occurs. * * @return true
if one of the players is a winner * and the winning indices are stored in the given * array. */ public boolean getWinningCells( int[] out ){ for( int i = 0; i < numTotals; ++i ){ int total = totals[i]; if( total == player1Wins || total == player2Wins ){ System.arraycopy( rowIndices, i * cellsPerRow, out, 0, cellsPerRow ); return true; } } return false; } /** * Returns whether or not the game is over. * * @return true
if the game is over, either because * someone has one or else there’s a tie. */ public boolean isGameOver(){ if( !gameStarted ) return true; if( getWinner() != NO_PLAYER ) return true; for( int i = 0; i < numCells; ++i ){ if( cells[i] == NO_PLAYER ) return false; } return true; } /** * Returns whether or not a game has been started. * * @return true
if a game has been started.
67957_Wiley_Giguere_AppA
250
10/17/2000 5:18 PM
Page 250
APPENDIX A */ public boolean isGameStarted(){ return gameStarted; } /** * Starts a new game of size 3. If a game is * currently under way it notifies any listeners that the existing game * is finishing before notifying them about the new game. */ public void newGame(){ newGame( 3 ); } /** * Starts a new game of the given size. If a game is * currently under way it notifies any listeners that the existing game * is finishing before notifying them about the new game. * * @param size the size of the game, the number of * cells on one side of a game square. */ public void newGame( int size ){ // First some sanity checking. // too small or too big.
We don’t want the board
if( size < 3 || size > 6 ){ size = 3; } // Tell anyone waiting that the game is now over. endGame(); // Figure out the dimensions we need to worry about. // The number of cells is n**2, the number of rows is 2*n+2. cellsPerRow = size; numCells = size * size; numTotals = 2 * size + 2; player1Wins = size * PLAYER_1; player2Wins = size * PLAYER_2; // Initialize the cells and totals.
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 251
Tic-Tac-Toe Source Code
251
if( cells == null || cells.length < numCells ){ cells = new byte[ numCells ]; } int i; for( i = 0; i < numCells; ++i ){ cells[i] = NO_PLAYER; } if( totals == null || totals.length < numTotals ){ totals = new int[ numTotals ]; } int initial = cellsPerRow * NO_PLAYER; for( i = 0; i < numTotals; ++i ){ totals[i] = NO_PLAYER; } calculateIndices(); // Tell everyone we’re ready and that a new game // has started. gameStarted = true; notifyGameStarted(); } /** * Notify listeners that the game is over. */ private void notifyGameOver(){ Enumeration e = listeners.elements(); while( e.hasMoreElements() ){ TicTacToeModelListener l = (TicTacToeModelListener) e.nextElement(); l.gameOver( this ); } } /** * Notify listeners that the game has started. */ private void notifyGameStarted(){ Enumeration e = listeners.elements(); while( e.hasMoreElements() ){ TicTacToeModelListener l = (TicTacToeModelListener) e.nextElement();
67957_Wiley_Giguere_AppA
252
10/17/2000 5:18 PM
Page 252
APPENDIX A l.gameStarted( this ); } } /** * Notify listeners that the game has been updated. */ private void notifyGameUpdated( int cell, int value ){ Enumeration e = listeners.elements(); while( e.hasMoreElements() ){ TicTacToeModelListener l = (TicTacToeModelListener) e.nextElement(); l.gameUpdated( this, cell, value ); } } /** * Quits an existing game, notifying any listeners * that the game is over. */ public void endGame(){ if( gameStarted ){ gameStarted = false; notifyGameOver(); } } /** * Removes a listener from this model. * * @param listener the listener to remove. */ public void removeListener( TicTacToeModelListener listener ){ listeners.removeElement( listener ); } /** * Sets the value of a cell. * * @param index the cell index. * @param value the cell value. */ public void setCellState( int index, int value ){ if( !gameStarted || index < 0 || index >= numCells ) return; if( cells[index] != NO_PLAYER ) return; cells[index] = (byte) value;
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 253
Tic-Tac-Toe Source Code calculateTotals(); notifyGameUpdated( index, value ); if( isGameOver() ){ endGame(); } } /** * Sets the value of a cell by row and column. * * @param row the row index of the cell. * @param col the column index of the cell. * @param value the cell value. */ public void setCellState( int row, int col, int value ){ setCellState( row * cellsPerRow + col, value ); } /** * The cells used by the game. */ private byte[] cells; /** * The number of cells per row. */ private int cellsPerRow; /** * Whether a game is active or not. */ private boolean gameStarted; /** * The vector of listeners. */ private Vector listeners = new Vector(); /** * The number of cells in the game. */ private int numCells; /**
253
67957_Wiley_Giguere_AppA
254
10/17/2000 5:18 PM
Page 254
APPENDIX A * The number of rows in the game. */ private int numTotals; /** * Player 1 is a winner. */ private int player1Wins; /** * Player 2 is a winner. */ private int player2Wins; /** * The indices for each row. */ private int[] rowIndices; /** * The running totals to determine who is winning. */ private int[] totals; }
TicTacToeModelListener The model is accompanied by a listener interface so that interested parties can receive notifications about games that are in progress: package com.ericgiguere.j2mebook.models; /** * Defines an event listener for the TicTacToeModel. * Classes that implement this interface are notified * of the game status held by a model. */ public interface TicTacToeModelListener { /** * A game has just finished. * who won.
The listener can ask the model
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 255
Tic-Tac-Toe Source Code
255
* * @param model the model triggering the event. */ void gameOver( TicTacToeModel model ); /** * A game has started. * * @param model the model triggering the event. */ void gameStarted( TicTacToeModel model ); /** * A cell * * @param * @param * @param */
in the game has been updated. model the model triggering the event. cell the index of the updated cell. value the new value of the cell.
void gameUpdated( TicTacToeModel model, int cell, int value ); }
TicTacToePlayer Finally, we define a listener that behaves like a player, selecting cells in response to the user’s own selections: package com.ericgiguere.j2mebook.models; import java.util.Random; /** * Defines an automatic tic-tac-toe player. This player works * by implementing the TicTacToeModelListener interface and * receiving notifications from a TicTacToeModel. When the * opponent sets a cell, the player sets a cell in response. */ public class TicTacToePlayer implements TicTacToeModelListener { /** * Constructs an automatic tic-tac-toe player. * * @param which which player number, either PLAYER_1 or PLAYER_2.
67957_Wiley_Giguere_AppA
256
10/17/2000 5:18 PM
Page 256
APPENDIX A */ public TicTacToePlayer( int which ){ whichPlayer = which; } /** * Fills the first empty cell in a row with the value * for this player. * * @param model the game model. * @param row the row index. */ private void fillRow( TicTacToeModel model, int row ){ model.getRowIndices( row, indices ); for( int j = 0; j < indices.length; ++j ){ if( model.getCellState( indices[j] ) == TicTacToeModel.NO_PLAYER ){ model.setCellState( indices[j], whichPlayer ); break; } } } /** * Called when a game is started, prepares some values based * on the current settings of the model. * * @param model the game model. */ public void gameStarted( TicTacToeModel model ){ totals = model.getTotals(); canWinValue = ( 2 * whichPlayer ) + TicTacToeModel.NO_PLAYER; dangerValue = ( -2 * whichPlayer ) + TicTacToeModel.NO_PLAYER; indices = new int[ model.getSize() ]; }
/** * Called whenever a cell is updated while a game is in progress. * The automatic player uses this notification to track the * opponent’s moves and to prepare a move in response. * * @param model the game model. * @param index the cell index. * @param value the cell’s new value. */ public void gameUpdated( TicTacToeModel model, int index, int value
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 257
Tic-Tac-Toe Source Code
257
){ // Ignore our own moves... if( value == whichPlayer ) return; // Get the updated totals and see if we can win by filing // in a row. Otherwise see if the opposing player is about // to win and fill in the appropriate row... model.fillTotals( totals ); int i; int n = totals.length; for( i = 0; i < n; ++i ){ if( totals[i] == canWinValue ){ fillRow( model, i ); return; } } for( i = 0; i < n; ++i ){ if( totals[i] == dangerValue ){ fillRow( model, i ); return; } } // No danger values, so choose a cell at random... int max = model.getCellCount(); while( !model.isGameOver() ){ int cell = ( generator.nextInt() % max ); if( model.getCellState( cell ) == TicTacToeModel.NO_PLAYER ){ model.setCellState( cell, whichPlayer ); return; } } } /** * Called when the game is over. * * @param model the game model. */
Clears out some values.
public void gameOver( TicTacToeModel model ){ totals = null; indices = null;
67957_Wiley_Giguere_AppA
258
10/17/2000 5:18 PM
Page 258
APPENDIX A } private private private private private private
int int[] int[] int int Random
whichPlayer; totals; indices; canWinValue; dangerValue; generator = new Random();
}
Palm-Specific Code The Palm version of tic-tac-toe defines just a single class in addition to the common ones we just listed. We discussed this class in Chapter 8.
TicTacToe The class is a spotlet that draws the tic-tac-toe game board and traps user input: // Copyright 2000 by Eric Giguere. // From Java 2 Micro Edition: Professional Developer’s Guide, // published by John Wiley & Sons. package com.ericgiguere.j2mebook.palm; import com.ericgiguere.j2mebook.models.*; import com.sun.kjava.*; /** * A simple tic-tac-toe game for the Palm port of the CLDC. * This game uses the unsupported com.sun.kjava classes * to do the drawing and to get user input. */ public class TicTacToe extends Spotlet implements DialogOwner, TicTacToeModelListener { /** * Starts our game. */ public static void main( String[] args ){ new TicTacToe(); }
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 259
Tic-Tac-Toe Source Code
259
/** * Constructs a tic-tac-toe game. */ public TicTacToe() { register( NO_EVENT_OPTIONS ); Graphics.getGraphics().clearScreen(); model = new TicTacToeModel(); model.addListener( this ); model.addListener( new TicTacToePlayer( TicTacToeModel.PLAYER_2 ) ); model.newGame(); } /** * Called when a dialog is dismissed. We re-register the spotlet * and start a new game. * * @param title the title of the dialog. */ public void dialogDismissed( String title ){ register( NO_EVENT_OPTIONS ); model.newGame(); } /** * Draws the tic-tac-toe grid. * * @param g the Graphics object. */ public void drawGrid( Graphics g ){ int i, x, y; x = cellWidth; y = cellHeight; for( i = 0; i < cellsPerRow - 1; ++i ){ g.drawLine( x, 0, x, screenHeight, g.PLAIN ); g.drawLine( 0, y, screenWidth, y, g.PLAIN ); x += cellWidth; y += cellHeight; } } /**
67957_Wiley_Giguere_AppA
260
10/17/2000 5:18 PM
Page 260
APPENDIX A * Draws each cell. * * @param g the Graphics object. */ public void drawPlayers( Graphics g ){ for( int i = 0; i < numCells; ++i ){ cells[i].paint( g ); } } /** * Called when the game is over. * with the result of the game. * * @param model the game model. */
Displays a dialog
public void gameOver( TicTacToeModel model ){ String text; switch( model.getWinner() ){ case TicTacToeModel.PLAYER_1: text = "Player 1 wins!"; break; case TicTacToeModel.PLAYER_2: text = "Player 2 wins!"; break; default: text = "A tie!"; break; } Dialog d = new Dialog( this, "Game Over", text, "OK" ); d.showDialog(); } /** * Called * * @param * @param * @param */
when a cell in the game is updated. model the game model. index the cell index. value the cell’s new value.
public void gameUpdated( TicTacToeModel model, int index, int value ){ Cell cell = cells[index]; cell.state = value; paint(); }
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 261
Tic-Tac-Toe Source Code /** * Called when a game is started. Clears the screen, * calculates the dimensions of the cells and then paints * the grid. * * @param model the game model. */ public void gameStarted( TicTacToeModel model ){ Graphics.getGraphics().clearScreen(); cellsPerRow = model.getSize(); numCells = cellsPerRow * cellsPerRow; cellHeight cellWidth
= screenHeight / cellsPerRow; = screenWidth / cellsPerRow;
cells = new Cell[ numCells ]; int i, j, y; for( i = 0, y = 0; i < numCells; i += cellsPerRow ){ for( j = 0; j < cellsPerRow; ++j ){ cells[i+j] = new Cell( cellWidth * j + cellsPerRow, y + cellsPerRow ); } y += cellHeight; } this.model = model; paint(); } /** * General game paint routine. * cells. */
Draws the grid and then the
public void paint(){ Graphics g = Graphics.getGraphics(); if( model != null ){ drawGrid( g ); drawPlayers( g ); } } /** * Handles pen presses, checking to see if the user * has pressed over an empty cell. *
261
67957_Wiley_Giguere_AppA
262
10/17/2000 5:18 PM
Page 262
APPENDIX A * @param x the X coordinate of the pen press. * @parma y the Y coordinate of the pen press. */ public void penDown( int x, int y ){ if( model != null && model.isGameStarted() ){ for( int i = 0; i < numCells; ++i ){ if( cells[i].contains( x, y ) ){ model.setCellState( i, TicTacToeModel.PLAYER_1 ); return; } } } } private private private private private private private private
int int int int int int TicTacToeModel Cell[]
cellsPerRow; numCells; cellHeight; cellWidth; screenHeight = 160; screenWidth = 160; model; cells;
//--------------------------------------------------------/** * Defines a simple inner class for holding the state and * the location of each cell. Since it’s an inner class * each instance has access to the private data of its * parent class, i.e. the cellHeight and cellWidth values. */ private class Cell { int state; int x; int y; /** * Constructs an empty cell at the given location. * * @param x the X value. * @param y the Y value. */ public Cell( int x, int y ){ state = TicTacToeModel.NO_PLAYER; this.x = x; this.y = y; } /**
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 263
Tic-Tac-Toe Source Code
263
* Determines whether or not the given point is in the * cell. * * @param px the X value. * @param py the Y value. * * @return true
if the point is within the cell. */ public boolean contains( int px, int py ){ return( px >= x && px <= x + cellWidth && py >= y && py <= y + cellHeight ); } /** * Paints a cell according to its state. * * @param g the graphics object. */ public void paint( Graphics g ){ if( state == TicTacToeModel.PLAYER_1 ){ g.drawLine( x, y, x+cellWidth-6, y+cellHeight-6, g.PLAIN ); g.drawLine( x+cellWidth-6, y, x, y+cellHeight-6, g.PLAIN ); } else if( state == TicTacToeModel.PLAYER_2 ){ g.drawBorder( x, y, cellWidth-6, cellHeight-6, g.PLAIN, g.RAISED ); } } } }
MIDP-Specific Code A MIDP version of the tic-tac-toe game is discussed in Chapter 9. It defines two classes in addition to the common code already listed.
TicTacToe This class defines the entry point for the MIDlet: package com.ericgiguere.j2mebook.midp; import com.ericgiguere.j2mebook.models.*;
67957_Wiley_Giguere_AppA
264
10/17/2000 5:18 PM
Page 264
APPENDIX A import javax.microedition.midlet.*; import javax.microedition.lcdui.*; /** * Defines a tic-tac-toe MIDlet that uses the TicTacToeModel * class to control the game logic. The actual user interface * is defined by TicTacToeUI. */ public class TicTacToe extends MIDlet implements CommandListener { private private private private
Display Command TicTacToeUI TicTacToeModel
display; exitCommand; gameScreen; model;
/** * Constructs the MIDlet. */ public TicTacToe() { display = Display.getDisplay( this ); exitCommand = new Command( "Exit", Command.SCREEN, 2 ); model = new TicTacToeModel(); } /** * Called whenever a Command is triggered. * * @param c the Command that was triggered. * @param s the display object active when it was triggered. */ public void commandAction( Command c, Displayable s ) { if( c == exitCommand ){ destroyApp( false ); notifyDestroyed(); } } /** * Called when the MIDlet is asked to destroy itself. * * @param unconditional if true
the MIDlet must * quit immediately. */ public void destroyApp( boolean unconditional ) { model.endGame(); }
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 265
Tic-Tac-Toe Source Code
265
/** * Called when the MIDlet starts. Creates the initial * screen and the attaches the appropriate listeners. */ public void startApp() { gameScreen = new TicTacToeUI( this ); model.addListener( gameScreen ); model.addListener( new TicTacToePlayer( TicTacToeModel.PLAYER_2 ) ); gameScreen.addCommand( exitCommand ); gameScreen.setListener( this ); display.setCurrent( gameScreen ); model.newGame(); } /** * Called when the MIDlet pauses. */ public void pauseApp() { } }
TicTacToeUI The user-interface code for the MIDP tic-tac-toe game is found in this class: package com.ericgiguere.j2mebook.midp; import com.ericgiguere.j2mebook.models.*; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; /** * Displays a user interface for a tic-tac-toe game. The state * of the game is stored in a TicTacToeModel instance, so this * class is responsible for drawing the grid and the cell values * and interpreting user input. */ public class TicTacToeUI extends Canvas implements TicTacToeModelListener {
67957_Wiley_Giguere_AppA
266
10/17/2000 5:18 PM
Page 266
APPENDIX A /** * Constructs a tic-tac-toe user interface. * * @param main the main tic-tac-toe class. */ public TicTacToeUI( TicTacToe main ){ application = main; screenHeight = getHeight(); screenWidth = getWidth(); } /** * Draws the tic-tac-toe grid. * * @param g the graphics object. */ public void drawGrid( Graphics g ){ int i, x, y; x = cellWidth; y = cellHeight; for( i = 0; i < cellsPerRow - 1; ++i ){ g.drawLine( x, 0, x, screenHeight ); g.drawLine( 0, y, screenWidth, y ); x += cellWidth; y += cellHeight; } } /** * Draws each cell’s value. * * @param g the graphics object. */ public void drawPlayers( Graphics g ){ for( int i = 0; i < numCells; ++i ){ cells[i].paint( g ); } } /** * Called when the game is over. * with the result of the game. * * @param model the game model. */
Displays an alert
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 267
Tic-Tac-Toe Source Code
267
public void gameOver( TicTacToeModel model ){ repaint(); Alert alert = new Alert( "Game Over" ); String text; switch( model.getWinner() ){ case TicTacToeModel.PLAYER_1: text = "Player 1 wins!"; break; case TicTacToeModel.PLAYER_2: text = "Player 2 wins!"; break; default: text = "A tie!"; break; } alert.appendString( text ); alert.setTime( Alert.FOREVER ); Display.getDisplay( application ).setCurrent( alert, this ); } /** * Called * * @param * @param * @param */
when a cell in the game is updated. model the game model. index the cell index. value the cell’s new value.
public void gameUpdated( TicTacToeModel model, int index, int value ){ Cell cell = cells[index]; cell.state = value; repaint( cell.x, cell.y, cellWidth, cellHeight ); serviceRepaints(); } /** * Called when a game is started. * Calculates the dimensions of the cells and then paints * the grid. * * @param model the game model. */ public void gameStarted( TicTacToeModel model ){ cellsPerRow = model.getSize(); numCells = cellsPerRow * cellsPerRow;
67957_Wiley_Giguere_AppA
268
10/17/2000 5:18 PM
Page 268
APPENDIX A cellHeight cellWidth
= screenHeight / cellsPerRow; = screenWidth / cellsPerRow;
cells = new Cell[ numCells ]; int i, j, y; for( i = 0, y = 0; i < numCells; i += cellsPerRow ){ for( j = 0; j < cellsPerRow; ++j ){ cells[i+j] = new Cell( cellWidth * j + cellsPerRow, y + cellsPerRow ); } y += cellHeight; } this.model = model; repaint(); } /** * Handles key presses, selecting a cell if the cell is empty. * * @param keyCode the key that was pressed. */ public void keyPressed( int keyCode ){ if( model == null || !model.isGameStarted() ) return; int index; for( index = 0; index < keypad.length; ++index ){ if( keypad[index] == keyCode ) break; } if( index < keypad.length ){ model.setCellState( index, TicTacToeModel.PLAYER_1 ); } } /** * Paints the grid and the cells. * * @param g the graphics object. */ public void paint( Graphics g ){ if( model != null ){ drawGrid( g ); drawPlayers( g ); }
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 269
Tic-Tac-Toe Source Code
269
} /** * Called whenever the screen is shown. Starts a new * game if called after the alert is displayed. */ protected void showNotify(){ if( model != null && !model.isGameStarted() ){ model.newGame(); repaint(); } } private private private private private private private private private private
int int int int int int TicTacToeModel TicTacToe Cell[] static final int[]
cellsPerRow; numCells; cellHeight; cellWidth; screenHeight; screenWidth; model; application; cells; keypad = new int[]{ KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, KEY_NUM8, KEY_NUM9 };
//--------------------------------------------------------/** * Defines a simple inner class for holding the state and * the location of each cell. Since it’s an inner class * each instance has access to the private data of its * parent class, i.e. the cellHeight and cellWidth values. */ private class Cell { int state; int x; int y; /** * Constructs an empty cell at the given location. * * @param x the X value. * @param y the Y value. */ public Cell( int x, int y ){
67957_Wiley_Giguere_AppA
270
10/17/2000 5:18 PM
Page 270
APPENDIX A state = TicTacToeModel.NO_PLAYER; this.x = x; this.y = y; } /** * Determines whether or not the given point is in the * cell. * * @param px the X value. * @param py the Y value. * * @return true
if the point is within the cell. */ public boolean contains( int px, int py ){ return( px >= x && px <= x + cellWidth && py >= y && py <= y + cellHeight ); } /** * Paints a cell according to its state. * * @param g the graphics object. */ public void paint( Graphics g ){ if( state == TicTacToeModel.PLAYER_1 ){ g.drawLine( x, y, x+cellWidth-6, y+cellHeight-6 ); g.drawLine( x+cellWidth-6, y, x, y+cellHeight-6 ); } else if( state == TicTacToeModel.PLAYER_2 ){ g.drawArc( x, y, cellWidth-6, cellHeight-6, 0, 360 ); } } } }
BlackBerry-Specific Code The BlackBerry version of tic-tac-toe game adapts the two MIDP classes for use with the RIM user interface components.
TicTacToe Again, this is the entry point to the application:
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 271
Tic-Tac-Toe Source Code
271
// Copyright 2000 by Eric Giguere. // From Java 2 Micro Edition: Professional Developer’s Guide, // published by John Wiley & Sons. package com.ericgiguere.j2mebook.rim; import import import import
com.ericgiguere.j2mebook.models.*; net.rim.device.api.ui.*; net.rim.device.api.ui.component.*; net.rim.device.api.system.*;
/** * Defines a tic-tac-toe RIM application that uses the TicTacToeModel * class to control the game logic. The actual user interface * is defined by TicTacToeUI. */ public class TicTacToe extends UiApplication { private TicTacToeUI gameScreen; private TicTacToeModel model; /** * Starts the application. */ public static void main( String[] args ){ TicTacToe app = new TicTacToe(); app.enterEventDispatcher(); } /** * Constructs the tic-tac-toe game. */ public TicTacToe() { model = new TicTacToeModel(); } /** * Called when the application starts. Creates the initial * screen and the attaches the appropriate listeners. */ public void activate() { gameScreen = new TicTacToeUI( this ); model.addListener( gameScreen ); model.addListener( new TicTacToePlayer( TicTacToeModel.PLAYER_2 ) ); model.newGame();
67957_Wiley_Giguere_AppA
272
10/17/2000 5:18 PM
Page 272
APPENDIX A pushScreen( gameScreen ); } }
TicTacToeUI The user interface is very similar to that of the MIDP version, except that it also allows cells to be selected using the thumbwheel: // Copyright 2000 by Eric Giguere. // From Java 2 Micro Edition: Professional Developer’s Guide, // published by John Wiley & Sons. package com.ericgiguere.j2mebook.rim; import import import import
com.ericgiguere.j2mebook.models.*; net.rim.device.api.ui.*; net.rim.device.api.ui.component.*; net.rim.device.api.system.*;
/** * Displays a user interface for a tic-tac-toe game. The state * of the game is stored in a TicTacToeModel instance, so this * class is responsible for drawing the grid and the cell values * and interpreting user input. */ public class TicTacToeUI extends FullScreen implements TicTacToeModelListener, MenuListener, Runnable { /** * The menu ID for the Close item. */ private static final int MENU_CLOSE = 0; /** * The menu ID for selecting the current cell. */ private static final int MENU_SELECT_CELL = 1; /** * Constructs a tic-tac-toe user interface. * * @param main the main tic-tac-toe class.
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 273
Tic-Tac-Toe Source Code
273
*/ public TicTacToeUI( TicTacToe main ){ super( false ); application = main; // Create a menu that we’ll popup later menu = new Menu(); menu.add( new MenuStringField( "Select Cell", MENU_SELECT_CELL ) ); menu.add( new MenuStringField( "Close", MENU_CLOSE ) ); menu.addMenuListener( this ); } /** * Draws the tic-tac-toe grid. * * @param g the graphics object. */ public void drawGrid( Graphics g ){ int i, x, y; x = cellWidth; y = cellHeight; for( i = 0; i < cellsPerRow - 1; ++i ){ g.drawLine( x, 0, x, screenHeight ); g.drawLine( 0, y, screenWidth, y ); x += cellWidth; y += cellHeight; } } /** * Draws each cell’s value. * * @param g the graphics object. */ public void drawPlayers( Graphics g ){ for( int i = 0; i < numCells; ++i ){ cells[i].paint( g ); } } /** * Called when the game is over. * with the result of the game. *
Displays an alert
67957_Wiley_Giguere_AppA
274
10/17/2000 5:18 PM
Page 274
APPENDIX A * @param model the game model. */ public void gameOver( TicTacToeModel model ){ doPaint(); String text; switch( model.getWinner() ){ case TicTacToeModel.PLAYER_1: text = "Player 1 wins!"; break; case TicTacToeModel.PLAYER_2: text = "Player 2 wins!"; break; default: text = "A tie!"; break; } // Inform the user about the win/loss/tie, then // push a request to start a new game on the // event queue.... Dialog.inform( text ); invalidate(); application.invokeLater( this ); } /** * Called * * @param * @param * @param */
when a cell in the game is updated. model the game model. index the cell index. value the cell’s new value.
public void gameUpdated( TicTacToeModel model, int index, int value ){ Cell cell = cells[index]; cell.state = value; invalidate( cell.x, cell.y, cellWidth, cellHeight ); } /** * Called when a game is started. * Calculates the dimensions of the cells and then paints * the grid. * * @param model the game model. */
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 275
Tic-Tac-Toe Source Code public void gameStarted( TicTacToeModel model ){ this.model = model; if( screenWidth != 0 ){ initializeCells(); } } /** * Initialize the cell information for a game. */ public void initializeCells(){ selectableCell = 0; cellsPerRow = model.getSize(); numCells = cellsPerRow * cellsPerRow; cellHeight cellWidth
= screenHeight / cellsPerRow; = screenWidth / cellsPerRow;
cells = new Cell[ numCells ]; int i, j, y; for( i = 0, y = 0; i < numCells; i += cellsPerRow ){ for( j = 0; j < cellsPerRow; ++j ){ cells[i+j] = new Cell( cellWidth * j + cellsPerRow, y + cellsPerRow ); } y += cellHeight; } cells[ selectableCell ].setSelectable( true ); invalidate(); } /** * Handles key presses, selecting a cell if the cell is empty. * * @param keyCode the key that was pressed. */ public boolean keyDown( int status, int time, char key ){ if( model == null || !model.isGameStarted() ) return false; int index = (int) key - '0'; if( index >= 0 && index < numCells ){ model.setCellState( index, TicTacToeModel.PLAYER_1 ); }
275
67957_Wiley_Giguere_AppA
276
10/17/2000 5:18 PM
Page 276
APPENDIX A return true; } /** * Called by the system when a popup menu closes * without the user selecting any of its items. * Removes the menu by popping it off the display * stack. * * @param menu the menu that just closed. */ public void menuClosed( Menu menu ){ application.popScreen(); } /** * Called by the system when the user selects * a popup menu item. Removes the menu and * then acts on the selection. * * @param menu the menu that was just closed. * @param field the selected field in the menu. */ public void menuSelected( Menu menu, Field field ){ application.popScreen(); switch( ((MenuStringField) field).getId() ){ case MENU_CLOSE: System.exit( 0 ); break; case MENU_SELECT_CELL: model.setCellState( selectableCell, TicTacToeModel.PLAYER_1 ); invalidate(); break; } } /** * Called to perform layout of the screen. * * @param width the screen’s width. * @param height the screen’s height. */ public void sublayout( int width, int height ){ screenHeight = height; screenWidth = width; setExtent( width, height );
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 277
Tic-Tac-Toe Source Code if( model != null ){ initializeCells(); } } /** * Paints the grid and the cells. * * @param g the graphics object. */ public void paint( Graphics g ){ if( model != null ){ drawGrid( g ); drawPlayers( g ); } } /** * Called whenever the screen is shown. Starts a new * game if called after the alert is displayed. */ public void onDisplay(){ if( model != null && !model.isGameStarted() ){ model.newGame(); } } /** * Starts a new game. */ public void run(){ model.newGame(); } /** * Moves the selectable cell to a new cell. * * @param offset the direction and number of * cells to move (negative for up/left, * positive for down/right). */ private void moveCell( int offset ){ cells[ selectableCell ].setSelectable( false ); selectableCell += offset; if( selectableCell >= numCells ){ selectableCell = 0; } else if( selectableCell < 0 ){
277
67957_Wiley_Giguere_AppA
278
10/17/2000 5:18 PM
Page 278
APPENDIX A selectableCell = numCells - 1; } cells[ selectableCell ].setSelectable( true ); invalidate(); } /** * Called when the user clicks the thumbwheel. * Opens the popup menu in response. * * @param status ignored. * @param time ignored. * @return true
to indicate it’s been handled. */ public boolean thumbClick( int status, int time ){ application.pushScreen( menu ); return true; } /** * Called when the user rolls the thumbwheel down. * Moves the selected cell in response. * * @param status ignored. * @param time ignored. * @parma amount ignored. * @return true
to indicate it’s been handled. */ public boolean thumbRollDown( int status, int time, int amount ){ moveCell( 1 ); return true; } /** * Called when the user rolls the thumbwheel up. * Moves the selected cell in response. * * @param status ignored. * @param time ignored. * @parma amount ignored. * @return true
to indicate it’s been handled. */ public boolean thumbRollUp( int status, int time, int amount ){ moveCell( -1 ); return true; } private int
cellsPerRow;
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 279
Tic-Tac-Toe Source Code private private private private private private private private private private
int int int int int TicTacToeModel TicTacToe Cell[] Menu int
279
numCells; cellHeight; cellWidth; screenHeight; screenWidth; model; application; cells; menu; selectableCell;
//--------------------------------------------------------/** * Defines a simple inner class for holding the state and * the location of each cell. Since it’s an inner class * each instance has access to the private data of its * parent class, i.e. the cellHeight and cellWidth values. */ private class Cell { int state; int x; int y; boolean selectable; /** * Constructs an empty cell at the given location. * * @param x the X value. * @param y the Y value. */ public Cell( int x, int y ){ state = TicTacToeModel.NO_PLAYER; this.x = x; this.y = y; selectable = false; } /** * Determines whether or not the given point is in the * cell. * * @param px the X value. * @param py the Y value. * * @return true
if the point is within the cell. */ public boolean contains( int px, int py ){
67957_Wiley_Giguere_AppA
280
10/17/2000 5:18 PM
Page 280
APPENDIX A return( px >= x && px <= x + cellWidth && py >= y && py <= y + cellHeight ); } /** * Paints a cell according to its state. * * @param g the graphics object. */ public void paint( Graphics g ){ g.clear( x, y, cellWidth-6, cellHeight-6 ); if( state == TicTacToeModel.PLAYER_1 ){ g.drawLine( x, y, x+cellWidth-6, y+cellHeight-6 ); g.drawLine( x+cellWidth-6, y, x, y+cellHeight-6 ); } else if( state == TicTacToeModel.PLAYER_2 ){ g.drawRect( x, y, cellWidth-6, cellHeight-6 ); } if( selectable ){ g.invert( x, y, cellWidth-6, cellHeight-6 ); } } /** * Sets the selectable state of the cell. * * @param sel the new selectable state. */ public void setSelectable( boolean sel ){ selectable = sel; } } }
Waba-Specific Code Although minor changes are required to make the TicTacToeModel and TicTacToePlayer classes work with Waba, we do not list the changes here. Refer to the CD-ROM for the updated classes. Here is the code for the new TicTacToe class, however: // Copyright 2000 by Eric Giguere. // From Java 2 Micro Edition: Professional Developer’s Guide, // published by John Wiley & Sons.
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 281
Tic-Tac-Toe Source Code
281
package com.ericgiguere.j2mebook.waba; import com.ericgiguere.j2mebook.models.*; import waba.fx.*; import waba.ui.*; /** * A simple tic-tac-toe game for Waba. */ public class TicTacToe extends MainWindow implements TicTacToeModelListener { /** * Constructs a tic-tac-toe game. */ public TicTacToe() { screenHeight = height; screenWidth = width; model = new TicTacToeModel(); model.addListener( this ); model.addListener( new TicTacToePlayer( TicTacToeModel.PLAYER_2 ) ); model.newGame(); } /** * Draws the tic-tac-toe grid. * * @param g the Graphics object. */ public void drawGrid( Graphics g ){ int i, x, y; x = cellWidth; y = cellHeight; for( i = 0; i < cellsPerRow - 1; ++i ){ g.drawLine( x, 0, x, screenHeight ); g.drawLine( 0, y, screenWidth, y ); x += cellWidth; y += cellHeight; } } /** * Draws each cell.
67957_Wiley_Giguere_AppA
282
10/17/2000 5:18 PM
Page 282
APPENDIX A * * @param g the Graphics object. */ public void drawPlayers( Graphics g ){ for( int i = 0; i < numCells; ++i ){ cells[i].paint( g ); } } /** * Called when the game is over. Sets the text to display * about the winner of the game. The message will be displayed * when the paint event is called. * * @param model the game model. */ public void gameOver( TicTacToeModel model ){ String text; switch( model.getWinner() ){ case TicTacToeModel.PLAYER_1: winnerText = "Player 1 wins!"; break; case TicTacToeModel.PLAYER_2: winnerText = "Player 2 wins!"; break; default: winnerText = "A tie!"; break; } } /** * Called * * @param * @param * @param */
when a cell in the game is updated. model the game model. index the cell index. value the cell’s new value.
public void gameUpdated( TicTacToeModel model, int index, int value ){ Cell cell = cells[index]; cell.state = value; repaint(); } /** * Called when a game is started.
Clears the screen,
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 283
Tic-Tac-Toe Source Code * calculates the dimensions of the cells and then paints * the grid. * * @param model the game model. */ public void gameStarted( TicTacToeModel model ){ damageRect( 0, 0, height, width ); cellsPerRow = model.getSize(); numCells = cellsPerRow * cellsPerRow; cellHeight cellWidth
= screenHeight / cellsPerRow; = screenWidth / cellsPerRow;
cells = new Cell[ numCells ]; int i, j, y; for( i = 0, y = 0; i < numCells; i += cellsPerRow ){ for( j = 0; j < cellsPerRow; ++j ){ cells[i+j] = new Cell( cellWidth * j + cellsPerRow, y + cellsPerRow ); } y += cellHeight; } this.model = model; repaint(); } /** * Handles key presses, selecting a cell if the cell is empty. * * @param keyCode the key that was pressed. */ public void keyPressed( int keyCode ){ if( model == null || !model.isGameStarted() ) return; if( keyCode < '0' || keyCode > '9' ) return; model.setCellState( keyCode - '0', TicTacToeModel.PLAYER_1 ); } /** * Called by Waba whenever an event occurs. * * @param e the event object with information about the event. */
283
67957_Wiley_Giguere_AppA
284
10/17/2000 5:18 PM
Page 284
APPENDIX A public void onEvent( Event e ){ if( model == null ) return; if( e instanceof KeyEvent ){ keyPressed( ((KeyEvent)e).key ); } else if( e instanceof PenEvent ){ PenEvent pe = (PenEvent) e; if( pe.type == PenEvent.PEN_DOWN ){ if( model.isGameStarted() ){ penDown( pe.x, pe.y ); } else { model.newGame(); } } } } /** * General game paint routine. Draws the grid and then the * cells. Also draws the winner text if the game is over. * * @param g the graphics object. */ public void onPaint( Graphics g ){ g.setColor( 0, 0, 0 ); if( model != null ){ drawGrid( g ); drawPlayers( g ); if( !model.isGameStarted() ){ g.fillRect( 10, 40, width-20, height-80 ); g.setColor( 255, 255, 255 ); g.drawText( winnerText, 15, 40 ); g.drawText( "Tap to start over", 15, 60 ); } } } /** * Handles pen presses, checking to see if the user * has pressed over an empty cell. * * @param x the X coordinate of the pen press. * @parma y the Y coordinate of the pen press. */ public void penDown( int x, int y ){ if( model != null && model.isGameStarted() ){ for( int i = 0; i < numCells; ++i ){
67957_Wiley_Giguere_AppA
10/17/2000 5:18 PM
Page 285
Tic-Tac-Toe Source Code if( cells[i].contains( x, y ) ){ model.setCellState( i, TicTacToeModel.PLAYER_1 ); return; } } } } private private private private private private private private private
int int int int int int TicTacToeModel Cell[] String
cellsPerRow; numCells; cellHeight; cellWidth; screenHeight; screenWidth; model; cells; winnerText;
//--------------------------------------------------------/** * Defines a simple inner class for holding the state and * the location of each cell. Since it’s an inner class * each instance has access to the private data of its * parent class, i.e. the cellHeight and cellWidth values. */ private class Cell { int state; int x; int y; /** * Constructs an empty cell at the given location. * * @param x the X value. * @param y the Y value. */ public Cell( int x, int y ){ state = TicTacToeModel.NO_PLAYER; this.x = x; this.y = y; } /** * Determines whether or not the given point is in the * cell. * * @param px the X value. * @param py the Y value.
285
67957_Wiley_Giguere_AppA
286
10/17/2000 5:18 PM
Page 286
APPENDIX A * * @return true
if the point is within the cell. */ public boolean contains( int px, int py ){ return( px >= x && px <= x + cellWidth && py >= y && py <= y + cellHeight ); } /** * Paints a cell according to its state. * * @param g the graphics object. */ public void paint( Graphics g ){ if( state == TicTacToeModel.PLAYER_1 ){ g.drawLine( x, y, x+cellWidth-6, y+cellHeight-6 ); g.drawLine( x+cellWidth-6, y, x, y+cellHeight-6 ); } else if( state == TicTacToeModel.PLAYER_2 ){ g.drawRect( x, y, cellWidth-6, cellHeight-6 ); } } } }
67957_Wiley_Giguere_About CD
10/17/2000 5:19 PM
Page 287
What’s on the CD-ROM?
O
n the CD-ROM, you’ll find:
■■
A beta copy of the Motorola iDEN SDK for Java
■■
An early access version of the Research In Motion BlackBerry Java Development Environment
■■
Borland’s JBuilder 3.5 Foundation, including a copy of the Handheld Express beta
■■
Other software, including a copy of kAWT and two XML parsers
■■
And, of course, the source code to the tic-tac-toe games
Consult the index.html file at the root of the CD for installation and usage instructions.
System Requirements Minimum system requirements: Windows 95, NT 4.0 or higher; 200 MHz Pentium; 64 MB RAM required. Recommended system requirements: Windows 95, NT 4.0, or higher; 500 MHz Pentium; and 128 MB RAM recommended depending on file sizes.
287
67957_Wiley_Giguere_About CD
288
10/17/2000 5:19 PM
Page 288
J A VA ™ 2 M I C R O E D I T I O N
Hard drive space: Consult the installation documentation for each third-party software on the CD-ROM for hard drive requirements. Peripherals: CD-ROM drive You also will need to have the following applications to make full use of the CDROM: a browser such as Microsoft Internet Explorer or Netscape Navigator to open the index.html file and to navigate the CD-ROM, an unzip utility to extract archived files, and a copy of Adobe Acrobat Reader 4.0 to read certain documents.
User Assistance and Information The software accompanying this book is being provided as is without warranty or support of any kind. Should you require basic installation assistance, or if your media is defective, please call our product support number at (212) 8506194 weekdays between 9 A.M. and 4 P.M. Eastern Standard Time. Or, we can be reached via e-mail at: [email protected]. To place additional orders or to request information about other Wiley products, please call (800) 879-4539.
67957_Wiley_Giguere_Index/Dis
10/17/2000 5:19 PM
Page 289
Index
A Abstract Windowing Toolkit, see AWT alternatives (to Java), 241—242 Waba, 227 bridge classes, 229 classes, compiling and running, 233 debugging programs, 235 foundation classes, 235—237 HelloWorld application, 233 installing, 230 runtime library, 228 samples (SDK), running, 231—232 Tic-Tac-Toe example, 237—238 virtual machine, 227—228 always-available devices, 14 networking, 15 APIs (application programming interfaces), MIDlet Suites, 111 applications descriptors, 113 lifecycles, 114 manifest attributes, 111
applets (features of Java 1.02), 41—42 application programming Interfaces, see APIs, 109 applications building RIM Blackberry J2ME implementation, 214—216, 218—220 smaller (programming strategies), 54—55 CLDC (Connected Limited Device Configuration) HelloWorld example, 136—137 HelloWorld Spotlet, 137 debugging (CLDC), 141—142 delivery dynamic (configurations), 91 sandbox CLDC support, 96 MIDlets, 113 HelloWorld (CLDC for Palm devices), 153—155 installing (JAR files), 55 Java 1.02, 43 lifecycles (MIDlets), 114 MIDP Early Access Release HelloMIDlet, 184, 186—187
Tic-Tac-Toe example, 187, 190 simplifying (programming strategies), 53—54 speed, 4 Waba debugging, 235 HelloWorld, 233 ARDIS, 15 attributes, manifest (MIDlets), 111 Automatic Player (CLDC for Palm devices), 171 avoiding exceptions (reducing memory usage at run time), 61 string concatenation (coding for performance), 63 thread synchronization (coding for performance), 64—65 AWT (Abastract Windowing Toolkit), MIDP UI APIclass, 115—116 B barcode readers (input methods), 12 289
67957_Wiley_Giguere_Index/Dis
290
10/17/2000 5:19 PM
Page 290
INDEX
battery operation, 7—8 Palm V, 14 Blackberry wireless handhelds, 201—203 classes, 222 IDE, 204—205 starting, 204 J2ME implementation, 213 applications, building, 214—216, 218—220 JDE installing, 203 samples, running, 211—212 network communication, 221 simulator, 208—210 Tic-Tac-Toe example, 222—225 Bluetooth, 15 bridge classes (Waba), 229 browsers (upgrading to Java 1.1), 47 building applications (programming strategies), 54—55 input method, 12 models (MVC), 66—67 C CDC configuration, 101, 103 cellular phones emulators (Motorola SDK for J2ME), 195—199 Ericsson T18s, 12 keypads, 12 simulators (MIDP Early Access Release), 180—182 central processing units (CPUs), 8 character-recognition software, 9 classes CLDC (Connected Limited Device Configuration), compiling and running, 134—135 files, 28, 30 Generic Connections (CLDC), 97—100 MIDP (Mobile Information Device Profile) HTTP connections, 123—124
Record Management System, 120—123 timer notifications, 124 MIDP Early Access Release (compiling and running), 183—184 MIDP user interface, 115 drawing and repainting, 119 MIDP UIAPIs and AWT, 115—116 screens and events, 116, 118 threading issues, 120 network connection Connector (CLDC for Palm devices), 165—167 HTTP (CLDC for Palm devices), 167 RIM Blackberry J2ME implementation, 222 updates in J2ME, 79 user interface (CLDC for Palm devices), 158—163 VM class loader, 35, 37 VM class verifier, 37—38 bridge, 229 foundation, 235—237 CLDC (Connected Limited Device Configuration), 91—93, 129—130 classes compiling and running, 134—135 Generic Connections, 98, 100 inherited, 97—98 debugging applications, 141—142 HelloWorld Spotlet, 137 installing, 130—131 JAM sample implementation, 139—140 language support, 94 memory usage, 139 Palm devices, 143 Automatic Player, 171 Color KVM, 172 Connector class (network connections), 165—167 databases, 163—165 development issues, 145
hardware specs, 146 HelloWorld application, 136—137, 153—155 HTTP connections (network connections), 167 installing, 150—151 Jbed MicroEdition, 173—174 JBuilder Handheld Express, 173 kAWT, 172 KVMulti application, 152 memory model, 147—148 model differences, 144—145 operating system, 146 Palm OS Emulator, 149 resetting, 148 samples, running, 151 Tic-Tac-Toe example, 167, 169—171 user interface classes, 158—163 samples, running, 131—133 sandbox support, 96 virtual machine support, 95 coding disassembling code, 28 Blackberry IDE, 206—207 with performance in mind, 62 local variables, 62—63 string concatenation, avoiding, 63 threads without synchronization, 64—65 Color KVM (CLDC for Palm devices), 172 CompactFlash Type II expansion slot, 7 compiling classes CLDC (Connected Limted Device Configuration), 134—135 MIDP Early Access Release, 183—184 Waba, 233 just-in-time (Java 1.1 features), 44
67957_Wiley_Giguere_Index/Dis
10/17/2000 5:19 PM
Page 291
INDEX
computing devices input/output, 8 memory capacity, 5 Palm V, 4 PDA, 4 CDC, 101, 103 CLDC (Connected Limited Device Configuration), 91, 93 Generic Connections classe, 98, 100 inherited classes, 97—98 language support, 94 sandbox support, 96 virtual machine support, 95 device families, 90 dynamic applicaiton delivery, 91 identifying, 91 configuring J2ME, 80—81 connected device families (configurations), 90 Connector class (CLDC for Palm devices), 165—167 cradles, 15 D data synchronization, 14 databases (CLDC for Palm devices), 163—165 debugging applications Blackberry IDE, 206—207 CLDC (Connected Limited Device Configuration), 141—142 Waba, 235 delivery, application (configurations), 91 devices Blackberry wireless handhelds, 201—203 classes, 222 IDE, 204—207 J2ME implementation, 213—216, 218—220 JDE, 203, 211—212 network communication, 221 simulator, 208—210 Tic-Tac-Toe example, 222—225 families (configurations), 90
MIDP user interface classes, 119 E Embedded Java vs. J2ME, 86 emulators cellular phone (Motorola SDK for J2ME), 195—199 Palm OS Emulator, 149 Ericsson T18s, 12 events (MIDP user interface classes), 116, 118 exceptions, avoiding (reducing memory usage at run time), 61 execution engine, 25 class loader, 25 class verifier, 25 garbage collector, 25, 33—34 Java ( native code interface), 25 virtual machine, 25—28, 32 class loader, 35, 37 class verifier, 37—38 disassembling Java bytecode, 28 native code interface, 38 pointers, 31 runtime checks, 31 security checks, 31 speed, 31 synchronization primitives, 32 F families, device (configurations), 90 files (class), 28, 30 form factor constraints on I/O methods, 14 small computing devices, 13 foundation classes (Waba), 235 I/O, 237 user interface, 236 Foundation Profile, 125 G Garbage collectors, 33—34 reducing memory at run time, 57 Generic Connections class (CLDC), 98, 100
291
H HelloMIDlet application (MIDP Early Access Release), 184, 186—187 HelloWorld application CLDC (Connected Limited Device Configuration) example, 136—137 for Palm devices, 153—155 Waba, 233 HelloWorld Spotlet, CLDC (Connected Limited Device Configuration) example, 137 Hewlett-Packard Jornada 430se, 7 HotSpot virtual machine, 78—79 HTTP connections CLDC for Palm devices, 167 MIDP classes, 123—124 I I/O Waba classes, 237 identifying configurations, 91 profiles, 107 implementations, CLDC (Connected Limited Device Configuration), 129—130 classes, compiling and running, 134—135 debugging applications, 141—142 HelloWorld application, 136—137 HelloWorld Spotlet, 137 installing, 130—131 JAM sample implementation, 139—140 memory usage, 139 samples, running, 131—133 indicator lights (output methods), 13 infrared communication, 15 infrared ports (output methods), 13 input methods barcode readers, 12 buttons, 12 character-recognition software, 9
67957_Wiley_Giguere_Index/Dis
292
10/17/2000 5:19 PM
Page 292
INDEX
input methods (cont.) joysticks, 12 keyboards, 10 keypads, 12 roller wheels, 12 touch-sensitive screens, 9 trackballs, 12 voice recognition, 12 input/output methods form factor constraints, 9, 14 small computing devices, 8 installing applications (JAR files), 55 Blackberry JDE, 203 CLDC (Connected Limited Device Configuration), 130—131 MIDP Early Access Release, 178—179 Motorola SDK for J2ME, 194 Waba, 230 J JAM sample implementation, CLDC (Connected Limited Device Configuration), 139—140 JAR (Java Archive) files (installing applications), 55 Java architecture, 23 execution engine, 25 class files, 28, 30 class loader, 25, 35, 37 class verifier, 25, 37—38 garbage collector, 25, 33—34 native code interface, 25, 38 virtual machine, 25—28, 31—32 runtime libraries, 39 Java 1.02, 40 applets, 41—42 applications, 43 Java 1.1, 43—44 browser upgrades, 47 database connectivity, 45 JavaBeans, 46 JRE (Java runtime environment), 48
just-in-time compiling, 44 object serialization, 45 RMI, 45 Servlets, 46 Java 2, 48—49 Java 2 Enterprise Edition, 49 Java 2 Standard Edition, 49 Java 2 Micro Edition (J2ME) alternatives to, 241—242 cellular phone emulator, 195—199 installing, 194 configurations, 89—90 CDC, 101, 103 CLDC, 91, 93—98, 100 device families, 90 dynamic applicaiton delivery, 91 identifying, 91 RIM Blackberry implementation, 213 classes, 222 network communication, 221 Tic-Tac-Toe example, 222—225 specifications, 77 class changes, 79 configurations, 80—81 HotSpot virtual machine, 78—79 KVM virtual machine, 81—85 profiles, 80—81 vs. Embedded Java, 86 vs. Java Card, 87 vs. Personal Java, 86 Java Archive, see JAR Java Card vs. J2ME, 87 Java runtime environment, see JRE Java Virtual Machine Specifications, see JVMS JavaBeans (Java 1.1 features), 46 Jbed MicroEdition (CLDC for Palm devices), 173—174 JBuilder Handheld Express (CLDC for Palm devices), 173 JLS (Java Language Specification), 19
joysticks, 12 JRE (Java runtime environment), 19 Java 1.1, 48 Java 1.1, 44 JVMS (Java Virtual Machine Specification), 19, 25 K kAWT (CLDC for Palm devices), 172 keyboards collapsibles, 12 input methods, 10 QWERTY, 11 keypads, 12 KVM virtual machine, 81—85 CLDC memory usage, 139 KVMulti application (CLDC for Palm devices), 152 L languages (CLDC support), 94 lazy instantiation (reducing memory usage at run time), 58 libraries, runtime, 39 local variables coding for performance, 62—63 CLDC for Palm devices, 155, 157 M manifest attributes (MIDlets), 111 memory capacity (small computing devices), 5 CLDC (Connected Limited Device Configuration) usage, 139 Palm devices, 147—148 using less at run time (programming strategies), 56—61 MIDlets, 109, 111 applications descriptors, 113 lifecycles, 114 manifest attributes, 111
67957_Wiley_Giguere_Index/Dis
10/17/2000 5:19 PM
Page 293
INDEX
MIDlet Suites, 111 application lifecycles, 114 application descriptors, 113 manifest attributes, 111 MIDP (Mobile Information Device Profile), 105—109 HTTP connections, 123—124 MIDlet Suites, 111 application descriptors, 113 manifest attributes, 111 MIDlets, 109, 111 application descriptors, 113 application lifecycles, 114 manifest attributes, 111 Record Management System class, 120—123 timer notifications, 124 user interface classes, 115 drawing and repainting, 119 MIDP UIAPIs and AWT, 115—116 screens and events, 116, 118 threading issues, 120 MIDP Early Access Release, 177—178 cellular phone simulator, 180—182 classes, compiling and running, 183—184 HelloMIDlet application, 184, 186—187 installing, 178—179 samples, running, 182 Tic-Tac-Toe example, 187, 190 MIDs (Mobile Information Devices), 108 mobitex, 15 model-view-controller, see MVC models, application (RIMBlackberry J2ME implementation), 219—220 Motorola SDK for J2ME, 193—195 cellular phone emulator, 195—199 installing, 194
MVC (model-viewcontroller), 65 building a model, 66—67 Tic-Tac-Toe example, 68—72 N native code interface execution engines, 25 Java execution engine, 38 networks, 14 always-available devices, 15 building smaller applications, 55 connectivity (RIM Blackberry J2ME implementation), 221 occasionally connected devices, 15 O objects reusing (reducing memory usage at run time), 59—61 serialization (Java 1.1 features), 45 occasionally connected devices, 15 offline storage, 5, 7 online storage, 5 operating systems (Palm devices), 146 Palm OS Emulator, 149 output methods audio signals, 13 indicator lights, 13 infrared ports, 13 screens, 12 P Palm devices, 143 CLDC (Connected Limited Device Configuration) Automatic Player, 171 Color KVM, 172 databases, 163—165 HelloWorld application, 153—155 HTTP connections (network connections), 167 installing, 150—151 Jbed MicroEdition, 173—174
293
JBuilder Handheld Express, 173 kAWT, 172 KVMulti application, 152 MakePalmApp options, 155, 157 samples, running, 151 Tic-Tac-Toe example, 167, 169—171 user interface classes, 158—163 development issues, 145 hardware specs, 146 memory model, 147—148 model differences, 144—145 operating system, 146 Palm OS Emulator, 149 Palm V organizer, 4, 9 Palm Vx, 7 resetting, 148 PDAs (personal digital assitants), 3, 5 PDA profile, 125 performance (coding strategies), 62 local variables, 62—63 string concatenation, avoiding, 63 threads without synchronization, 64—65 personal digital assistants, see PDAs Personal Java vs. J2ME, 86 Personal Profile, 126 pointers (Java virtual machine), 31 processor power, 7—8 profiles, 105 Foundation, 125 identifying, 107 J2ME, 80—81 MIDP Early Access Release, 177—178 cellular phone simulator, 180—182 classes, compiling and running, 183—184 HelloMIDlet application, 184, 186—187 installing, 178—179 samples, running, 182 Tic-Tac-Toe example, 187, 190
67957_Wiley_Giguere_Index/Dis
294
10/17/2000 5:19 PM
Page 294
INDEX
purpose of, 106 MIDP (Mobile Information Device Profile), 105—109 MIDlet Suites, 111—114 MIDlets, 109—114 Record Management System class, 120—123 timer notifications, 124 user interface classes, 115—120 PDA, 125 Personal, 126 RMI, 126 programming strategies (small devices), 51—52 building smaller applications, 54—55 less memory at run time, 56—61 moving computations to servers, 52 MVC (model-viewcontroller), 65—72 simplifying applications, 53—54 Psion Series 7, 7 R Record Management System (MIDP classes), 120—123 releasing resources (reducing memory usage at run time), 59 repainting MIDP user interface classes, 119 resetting Palm devices, 148 resources, releasing early (reducing memory usage at run time), 59 reusing objects (reducing memory usage at run time), 59—61 RIM 957 Wireless Handheld, 11 RIM Blackberry wireless handhelds, 201—203 classes, 222 IDE, 204—205 running and debugging code, 206—207 starting, 204 J2ME implementation, 213 applications, building, 214—216, 218—220
JDE installing, 203 samples, running, 211—212 network communication, 221 simulator, 208—210 Tic-Tac-Toe example, 222—225 RMI (Java 1.1), 45 RMI Profile, 126 roller wheels, 12 runtime using less memory (programming strategies), 56—61 checks (Java virtual machine), 31 classes CLDC (Connected Limited Device Configuration), 134—135 MIDP Early Access Release, 183—184 Waba, 233 libraries, 39 Waba, 228 samples CLDC (Connected Limited Device Configuration), 131—133 CLDC for Palm devices, 151 MIDP Early Access Release, 182 SDKWaba samples, 231—232 S samples, running, 231—232 CLDC (Connected Limited Device Configuration), 131—133 CLDC for Palm devices, 151 MIDP Early Access Release, 182 RIM Blackberry handheld JDE, 211—212 sandboxes (CLDC support), 96 scalar types (reducing memory usage), 56 screens MIDP user interface classes, 116, 118 output methods, 12 security checks (Java virtual machine), 31 serial communication, 15
serialization, object (Java 1.1), 45 servers, moving computationintensive tasks to, 52 servlets (Java 1.1), 46 simulators (RIM Blackberry handhelds), 208—210 size, applications, reducing, 54—55 small computing devices cellular phones, 12 Ericsson T18s, 12 form factor, 13 Hewlett-Packard Jornada 430se, 5 IBM Microdrive, 7 input/output, 8 memory capacity, 5 networking, 14 Palm V, 4, 9, 14 Palm Vx, 7 PDA, 4 processor power, 7—8 programming strategies, 51—52 building smaller applications, 54—55 coding with performance in mind, 62—65 less memory at run time, 56—61 moving computations to servers, 52 MVC (model-viewcontroller), 65—72 simplifying applications, 53—54 Psion Series 7, 7 RIM 950 Wireless Handheld, 11 Sony’s Memory Stick, 7 storage capacity, 5 Web pads, 5 Sony’s Memory Stick, 7 specifications, Java 2 Micro Edition (J2ME), 77 class changes, 79 configurations, 80—81 Embedded Java comparisons, 86 HotSpot virtual machine, 78—79 Java Card comparisons, 87
67957_Wiley_Giguere_Index/Dis
10/17/2000 5:19 PM
Page 295
INDEX
KVM virtual machine, 81—85 Personal Java comparisons, 86 speed applications, 4 Java virtual machine, 31 Spotlet Model (CLDC for Palm devices), 158 storage capacities, 5 string concatenation, avoiding (coding for performance), 63 Sun’s runtime environment, see JRE synchronization coding with threads, 64—65 primitives (Java virtual machine), 32 T third-party tools Color KVM, 172 Jbed MicroEdition, 173—174 JBuilder Handheld Express, 173 kAWT, 172 threads coding for performance (avoiding synchronization), 64—65 MIDP user interface classes, 120 thumbwheels, see roller wheels Tic-Tac-Toe example CLDC for Palm devices, 167, 169—171 MIDP Early Access Release, 187, 190
RIM Blackberry J2ME implementation, 222—225 Waba, 237—238 timer notifications (MIDP classes), 124 touch-sensitive screens (input methods), 9 trackballs, 12 U Universal Serial Bus (USB) standard, 15 UP APIs (MIDP user interface classes), 115—116 users interface classes CLDC for Palm devices, 158—163 Waba, 236 MIDP interface classes, 115 drawing and repainting, 119 MIDP UIAPIs and AWT, 115—116 screens and events, 116, 118 threading issues, 120 V variables, local (coding for performance), 62—63 verifying classes (Java VM), 37—38 versions (Java) 1.02, 40—43 1.1, 43—48 2, 48—49 virtual machines, 25—28, 32 class files, 28, 30 class loader, 35, 37
295
class verifier, 37—38 CLDC support, 95 disassembling Java bytecode, 28 execution engines, 25 garbage collector, 25, 33—34 HotSpot, 78—79 KVM, 81—85 native code interface, 38 pointers, 31 runtime checks, 31 security checks, 31 speed, 31 synchronization primitives, 32 voice recognition, 12 W Waba, 227 applications debugging, 235 HelloWorld, 233 classes bridge, 229 compiling and running, 233 foundation, 235—237 installing, 230 runtime library, 228 samples (SDK), running, 231—232 Tic-Tac-Toe example, 237—238 virtual machine, 227—228 Waba.fx class, 236 Web pads, 5
67957_Wiley_Giguere_Index/Dis
10/17/2000 5:19 PM
Page 296
CUSTOMER NOTE: IF THIS BOOK IS ACCOMPANIED BY SOFTWARE, PLEASE READ THE FOLLOWING BEFORE OPENING THE PACKAGE. This software contains files to help you utilize the models described in the accompanying book. By opening the package, you are agreeing to be bound by the following agreement: This software product is protected by copyright and all rights are reserved by the author, John Wiley & Sons, Inc., or their licensors. You are licensed to use this software as described in the software and the accompanying book. Copying the software for any other purpose may be a violation of the U.S. Copyright Law. This software product is sold as is without warranty of any kind, either express or implied, including but not limited to the implied warranty of merchantability and fitness for a particular purpose. Neither Wiley nor its dealers or distributors assumes any liability for any alleged or actual damages arising from the use of or the inability to use this software. (Some states do not allow the exclusion of implied warranties, so the exclusion may not apply to you.)