• | Table of Contents
• | Index
Programming Wireless Devices with the Java™ 2 Platform, Micro Edition, Second Edition
By Roger Riggs, Antero Taivalsaari, Jim Van Peursem, Jyri Huopaniemi, Mark Patel, Aleksi Uotila, Jim Holliday Editor
Publisher | : Addison Wesley
Pub Date | : June 13, 2003
ISBN | : 0-321-19798-4
Pages | : 464

This book presents the Java(TM) 2 Platform, Micro Edition (J2ME(TM)) standards that support the development of applications for consumer devices such as mobile phones, two-way pagers, and wireless personal organizers. To create these standards, Sun collaborated with such consumer device companies as Motorola, Nokia, NTT DoCoMo, Research In Motion, Samsung, Siemens, Sony Ericsson, and many others. The result is a highly portable, small-footprint application development environment that brings the unique capabilities of Java technology, including platform independence and enhanced security, to the rapidly growing wireless market.

This definitive Java(TM) Series guide provides a programmer's introduction to the Java 2 Platform, Micro Edition. It presents a general description of wireless technology and an overview of the J2ME platform. In addition, the book details the Connected Limited Device Configuration (CLDC) version 1.1 and the Mobile Information Device Profile (MIDP) version 2.0, the standards that define the Java platform features and libraries for wireless, resource-constrained devices.

Written by a team of authors that includes the original J2ME technology experts from Sun, Motorola, and Nokia, this book provides a description of the Java 2 Platform, Micro Edition, as well as practical implementation advice.

The Java(TM) Series is supported, endorsed, and authored by the creators of the Java technology at Sun Microsystems, Inc. It is the official place to go for complete, expert, and definitive information on Java technology. The books in this Series provide the inside information you need to build effective, robust, and portable applications and applets. The Series is an indispensable resource for anyone targeting the Java(TM) 2 platform.


• | Table of Contents
• | Index
Programming Wireless Devices with the Java™ 2 Platform, Micro Edition, Second Edition
By Roger Riggs, Antero Taivalsaari, Jim Van Peursem, Jyri Huopaniemi, Mark Patel, Aleksi Uotila, Jim Holliday Editor
Publisher | : Addison Wesley
Pub Date | : June 13, 2003
ISBN | : 0-321-19798-4
Pages | : 464

Copyright
The Java™ Series
 | The Jini™ Technology Series
 | The Java™ Series, Enterprise Edition
Figures
Foreword
Preface
 | Intended Audience
 | Objectives of This Book
 | How This Book Is Organized
 | Related Literature and Helpful Web Pages
Acknowledgments
Chapter 1. Introduction
 | Section 1.1. The Wireless Internet Revolution
 | Section 1.2. Why Java™ Technology for Wireless Devices?
 | Section 1.3. A Bit of History
 | Section 1.4. J2ME™ Standardization Efforts
Chapter 2. Overview of Java 2 Platform, Micro Edition (J2ME™)
 | Section 2.1. Java 2 Platform
 | Section 2.2. Java 2 Platform, Micro Edition (J2ME)
 | Section 2.3. Key Concepts of the J2ME Architecture
 | Section 2.4. Evolution of the J2ME Platform
Chapter 3. Goals, Requirements, and Scope
 | Section 3.1. High-Level Goals
 | Section 3.2. Target Devices
 | Section 3.3. General Notes on Consumer Devices and Embedded Systems
 | Section 3.4. Requirements
 | Section 3.5. Scope of the CLDC and MIDP Standards
Chapter 4. Connected Limited Device Configuration
 | Section 4.1. CLDC Expert Groups
 | Section 4.2. CLDC Architecture, Application Model, and Security
 | Section 4.3. Java Language Specification Compatibility
 | Section 4.4. Java Virtual Machine Specification Compatibility
 | Section 4.5. New for CLDC 1.1
Chapter 5. CLDC Libraries
 | Section 5.1. Background and Goals
 | Section 5.2. Classes Derived from Java 2 Standard Edition
 | Section 5.3. CLDC-Specific Classes
 | Section 5.4. New for CLDC 1.1
Chapter 6. Mobile Information Device Profile
 | Section 6.1. MIDP Expert Groups
 | Section 6.2. Areas Covered by the MIDP Specification
Chapter 7. MIDP Application Model
 | Section 7.1. MIDlets
 | Section 7.2. MIDlet Suites
 | Section 7.3. New for MIDP 2.0
Chapter 8. MIDP User Interface Libraries
 | Section 8.1. MIDP UI Compared to Desktop AWT
 | Section 8.2. Structure of the MIDP User Interface API
 | Section 8.3. Display
 | Section 8.4. Displayables
 | Section 8.5. Commands
 | Section 8.6. Advanced Topics
 | Section 8.7. New for MIDP 2.0
Chapter 9. MIDP High-Level User Interface – Screen
 | Section 9.1. List
 | Section 9.2. TextBox
 | Section 9.3. Alert
 | Section 9.4. Form
 | Section 9.5. New for MIDP 2.0
Chapter 10. MIDP High-Level User Interface – Form
 | Section 10.1. Item
 | Section 10.2. StringItem
 | Section 10.3. ImageItem
 | Section 10.4. TextField
 | Section 10.5. DateField
 | Section 10.6. ChoiceGroup
 | Section 10.7. Gauge
 | Section 10.8. CustomItem
 | Section 10.9. Form Layout
 | Section 10.10. New for MIDP 2.0
Chapter 11. MIDP Low-Level User Interface Libraries
 | Section 11.1. The Canvas API
 | Section 11.2. Low-Level API for Events in Canvases
 | Section 11.3. Graphics
 | Section 11.4. Creating and Using Images
 | Section 11.5. Drawing Primitives
 | Section 11.6. New for MIDP 2.0
Chapter 12. MIDP Game API
 | Section 12.1. The GameCanvas API
 | Section 12.2. Layers
 | Section 12.3. Sprites
 | Section 12.4. TiledLayer
 | Section 12.5. LayerManager
 | Section 12.6. Collision Detection
 | Section 12.7. Sample Code: A Simple Game
 | Section 12.8. New for MIDP 2.0
Chapter 13. MIDP Sound API
 | Section 13.1. Overview of the MIDP 2.0 Sound API
 | Section 13.2. Player Creation and Management
 | Section 13.3. Media Controls
 | Section 13.4. Enhanced Media Support Using the Mobile Media API
 | Section 13.5. New for MIDP 2.0
Chapter 14. MIDP Persistence Libraries
 | Section 14.1. The Record Management System
 | Section 14.2. Manipulating Record Stores and Records
 | Section 14.3. Sample Code (RMSMIDlet.java)
 | Section 14.4. New for MIDP 2.0
Chapter 15. MIDP Networking and Serial Communications
 | Section 15.1. Characteristics of Wireless Data Networks
 | Section 15.2. Network Interface Considerations
 | Section 15.3. The HttpConnection Interface
 | Section 15.4. Sample Code (NetClientMIDlet.java)
 | Section 15.5. SocketConnection
 | Section 15.6. ServerSocketConnection
 | Section 15.7. UDPDatagramConnection
 | Section 15.8. CommConnection
 | Section 15.9. New for MIDP 2.0
Chapter 16. Secure Networking
 | Section 16.1. Checking the Security Properties of a Connection
 | Section 16.2. HttpsConnection
 | Section 16.3. SecureConnection
 | Section 16.4. MIDP X.509 Certificate Profile
 | Section 16.5. New for MIDP 2.0
Chapter 17. Event-Driven Application Launch
 | Section 17.1. Alarm-Based MIDlet Launch
 | Section 17.2. Network-Based MIDlet Launch
 | Section 17.3. Listening and Launching
 | Section 17.4. Handling Connections after Launch
 | Section 17.5. Security of the Push Registry
 | Section 17.6. Sample Usage Scenarios
 | Section 17.7. New for MIDP 2.0
Chapter 18. Security for MIDlet Suites
 | Section 18.1. Assumptions
 | Section 18.2. Sandbox for Untrusted MIDlet Suites
 | Section 18.3. Trusted MIDlet Suite Security Model
 | Section 18.4. APIs That Are Not Security Sensitive
 | Section 18.5. Establishing Trust for MIDlet Suites by Using X.509 PKI
 | Section 18.6. Recommended Security Policy for GSM/UMTS Devices
 | Section 18.7. New for MIDP 2.0
Chapter 19. MIDlet Deployment
 | Section 19.1. MIDlet Suites
 | Section 19.2. MIDP System Software
 | Section 19.3. Over-the-Air User-Initiated Provisioning
 | Section 19.4. New for MIDP 2.0
Chapter 20. Additional MIDP APIs
 | Section 20.1. Timer Support
 | Section 20.2. System Properties
 | Section 20.3. Application Resource Files
 | Section 20.4. Exiting a MIDlet
Chapter 21. Summary
References
Appendix A. CLDC Application Programming Interface
 | Almanac Legend
 | CLDC Almanac
Appendix B. MIDP Application Programming Interface
 | MIDP Almanac
Index


Copyright

Copyright © 2003 Sun Microsystems, Inc.

4150 Network Circle, Santa Clara, California 95054, U.S.A.

All rights reserved.

Sun Microsystems, Inc. has intellectual property rights relating to implementations of the technology described in this publication. In particular, and without limitation, these intellectual property rights may include one or more U.S. patents, foreign patents, or pending applications. Sun, Sun Microsystems, the Sun logo, J2ME, Java Card, and all Sun and Java based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc., in the United States and other countries. UNIX is a registered trademark in the United States and other countries, exclusively licensed through X/Open Company, Ltd.

THIS PUBLICATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.

THIS PUBLICATION COULD INCLUDE TECHNICAL INACCURACIES OR TYPOGRAPHICAL ERRORS. CHANGES ARE PERIODICALLY ADDED TO THE INFORMATION HEREIN; THESE CHANGES WILL BE INCORPORATED IN NEW EDITIONS OF THE PUBLICATION. SUN MICROSYSTEMS, INC. MAY MAKE IMPROVEMENTS AND/OR CHANGES IN THE PRODUCT(S) AND/OR THE PROGRAM(S) DESCRIBED IN THIS PUBLICATION AT ANY TIME.

The publisher offers discounts on this book when ordered in quantity for bulk purchases and special sales. For more information, please contact U.S. Corporate and Government Sales, (800) 382-3419, corpsales@pearsontechgroup.com.

For sales outside of the U.S., please contact International Sales, (317) 581-3793, interntional@pearsontechgroup.com.

Visit Addison-Wesley on the Web: www.awprofessional.com

Library of Congress Cataloging-in-Publication Data

Programming wireless devices with the Java 2 Platform : micro edition /Roger Riggs ... [et al.]

p. cm.

ISBN 0-321-19798-4 (alk. paper)

1. Wireless communication systems. 2. Java (Computer program language) I. Riggs, Roger.

TK5103.2.P75 2003

005.2'762—dc21

2003010117

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. Printed in the United States of America. Published simultaneously in Canada.

For information on obtaining permission for use of material from this work, please submit a written request to Pearson Education, Inc., Rights and Contracts Department, 75 Arlington Street, Suite 300, Boston, MA 02116, Fax: (617) 848-7047.

Text printed on recycled paper

1 2 3 4 5 6 7 8 9 10—CRS—0706050403

First printing, June 2003


The Java™ Series

Lisa Friendly, Series Editor

Tim Lindholm, Technical Editor

Ken Arnold, Technical Editor of The JiniTM Technology Series

Jim Inscore, Technical Editor of The JavaTM Series, Enterprise Edition http://www.javaseries.com

Eric Armstrong, Stephanie Bodoff, Debbie Carson, Maydene Fisher, Dale Green, Kim Haase
The Java™ Web Services Tutorial

Ken Arnold, James Gosling, David Holmes
The Java™ Programming Language, Third Edition

Cindy Bloch, Annette Wagner
MIDP 2.0 Style Guide

Joshua Bloch
Effective Java™ Programming Language Guide

Mary Campione, Kathy Walrath, Alison Huml
The Java™ Tutorial, Third Edition: A Short Course on the Basics

Mary Campione, Kathy Walrath, Alison Huml,Tutorial Team
The Java™ Tutorial Continued: The Rest of the JDK™

Patrick Chan
>The Java™ Developers Almanac 1.4, Volume 1

Patrick Chan
The Java™ Developers Almanac 1.4, Volume 2

Patrick Chan, Rosanna Lee
The Java™ Class Libraries, Second Edition, Volume 2: java.applet, java.awt, java.beans

Patrick Chan, Rosanna Lee, Doug Kramer
The Java™ Class Libraries, Second Edition, Volume 1: java.io, java.lang, java.math, java.net, java.text, java.util

Patrick Chan, Rosanna Lee, Doug Kramer
The Java Class Libraries, Second Edition, Volume 1: Supplement for the Java™ 2 Platform, Standard Edition, v1.2

Kirk Chen, Li Gong
Programming Open Service Gateways with Java™ Embedded Server

Zhiqun Chen
Java Card™ Technology for Smart Cards: Architecture and Programmer's Guide

Maydene Fisher, Jon Ellis, Jonathan Bruce
JDBC™ API Tutorial and Reference, Third Edition

Li Gong, Gary Ellison, Mary Dageforde
Inside Java™ 2 Platform Security, Second Edition: Architecture, API Design, and Implementation

James Gosling, Bill Joy, Guy Steele, Gilad Bracha
The Java™ Language Specification, Second Edition

Doug Lea
Concurrent Programming in Java™, Second Edition: Design Principles and Patterns

Rosanna Lee, Scott Seligman
JNDI API Tutorial and Reference: Building Directory-Enabled Java™ Applications

Sheng Liang
The Java™ Native Interface: Programmer's Guide and Specification

Tim Lindholm, Frank Yellin
The Java™ Virtual Machine Specification, Second Edition

Roger Riggs, Antero Taivalsaari, Jim Van Peursem, Jyri Huopaniemi, Mark Patel, Aleksi Uotila
Programming Wireless Devices with the Java™ 2 Platform, Micro Edition, Second Edition

Henry Sowizral, Kevin Rushforth, Michael Deering
The Java 3D™ API Specification, Second Edition

Sun Microsystems, Inc.
Java™ Look and Feel Design Guidelines: Advanced Topics

Kathy Walrath, Mary Campione
The JFC Swing Tutorial: A Guide to Constructing GUIs

Seth White, Maydene Fisher, Rick Cattell, Graham Hamilton, Mark Hapner
JDBC™ API Tutorial and Reference, Second Edition: Universal Data Access for the Java™ 2 Platform

Steve Wilson, Jeff Kesselman
Java™ Platform Performance: Strategies and Tactics


The Jini™ Technology Series

Eric Freeman, Susanne Hupfer, Ken Arnold
JavaSpaces™ Principles, Patterns, and Practice


The Java™ Series, Enterprise Edition

Stephanie Bodoff, Dale Green, Kim Haase, Eric Jendrock, Monica Pawlan, Beth Stearns
The J2EE™ Tutorial

Rick Cattell, Jim Inscore, Enterprise Partners
J2EE™ Technology in Practice: Building Business Applications with the Java™ 2 Platform, Enterprise Edition

Mark Hapner, Rich Burridge, Rahul Sharma, Joseph Fialli, Kim Haase
Java™ Message Service API Tutorial and Reference: Messaging for the J2EE™ Platform

Inderjeet Singh, Beth Stearns, Mark Johnson, Enterprise Team
Designing Enterprise Applications with the Java™ 2 Platform, Enterprise Edition

Vlada Matena, Sanjeev Krishnan, Linda DeMichiel, Beth Stearns
Applying Enterprise JavaBeans™ 2.1, Second Edition: Component-Based Development for the J2EE™ Platform

Bill Shannon, Mark Hapner, Vlada Matena, James Davidson, Eduardo Pelegri-Llopart, Larry Cable, Enterprise Team
Java™ 2 Platform, Enterprise Edition: Platform and Component Specifications

Rahul Sharma, Beth Stearns, Tony Ng
J2EE™ Connector Architecture and Enterprise Application Integration


Figures

Figure 2.1 Java 2 Platform editions and their target markets

Figure 2.2 Software layers in a J2ME device

Figure 2.3 Relationship between J2ME configurations and Java 2 Standard Edition

Figure 3.1 Downloading customized services

Figure 3.2 CLDC and MIDP target devices

Figure 3.3 One-handed, two-handed, and stylus-operated mobile information devices

Figure 4.1 Architecture overview of a CLDC target device

Figure 4.2 Two-phase class file verification in CLDC

Figure 5.1 Connection interface hierarchy

Figure 7.1 MIDlet states and state transitions

Figure 8.1 MIDP user interface class hierarchy

Figure 10.1 General principle of Form layout

Figure 10.2 Item layout policy dictated by the device implementation

Figure 10.3 Applying vertical and horizontal layout directives

Figure 11.1 Pixel coordinate system showing the pixel at (4,3)

Figure 11.2 Example of the getRGB method

Figure 11.3 The anchor points for image rendering

Figure 11.4 The anchor points for text rendering

Figure 11.5 Example of the drawLine method

Figure 11.6 Example of the drawArc method

Figure 11.7 Example of the fillArc method

Figure 11.8 Example of the drawRect method

Figure 11.9 Example of the fillRect method

Figure 11.10 Example of the drawRoundRect method

Figure 11.11 Example of the fillRoundRect method

Figure 11.12 Example of the fillTriangle method

Figure 11.13 Example of the drawImage method

Figure 11.14 Transforms for drawing Images

Figure 11.15 Example of the drawRegion method

Figure 11.16 Example of the drawRGB method

Figure 11.17 Example of the copyArea method

Figure 12.1 Game loop flowchart

Figure 12.2 Frames can be arranged in various ways within an Image

Figure 12.3 Each frame in the Image is assigned an index

Figure 12.4 Example of a special frame sequence

Figure 12.5 The reference pixel with a pushpin in its center

Figure 12.6 The reference pixel acts as the center for transforms applied to a Sprite

Figure 12.7 A TiledLayer's static tile set is obtained from an Image

Figure 12.8 The TiledLayer's cells filled with the desired tile indices

Figure 12.9 Appearance of the TiledLayer

Figure 12.10 An update to an animated tile is reflected in all cells that reference it

Figure 12.11 Setting the view window

Figure 12.12 The contents of the view window drawn at a specific location

Figure 12.13 Setting a collision rectangle

Figure 12.14 Boundary-level collision detection

Figure 12.15 Pixel-level collision detection

Figure 12.16 A screen shot from the simple game

Figure 13.1 Overview of MIDP Sound API Architecture

Figure 13.2 Class diagram of the MIDP Sound API

Figure 13.3 MIDP Sound API Player state diagram

Figure 14.1 Structure of a record store

Figure 14.2 Separation of RMS name spaces

Figure 19.1 MIDlet suite name spaces

Figure 19.2 OTA download sequence


Foreword

"If a program is useful,
it will have to be changed."

—ACM SIGPLAN Notices (vol 2, no. 2), 1965

"To attain knowledge, add things every day;
to obtain wisdom, remove things every day."

—Lao-tsu, Tao Te Ching

"One must learn by doing the thing;
For though you think you know it,
you have no certainty until you try."

—Sophocles, Trachiniae

With the delivery of the Java™ 2 Platform, Micro Edition (J2ME™), Java technology has come full circle. The Java technology we know today originally sprang from a project whose goal was to investigate the potential impact of digital technologies outside the mainstream of the computer industry. It was clear that this big expanse of interesting territory was the space close to everyday people. Consumer electronics, telephony, and embedded systems were increasingly becoming a part of the fabric of everyday life.

Being a group with a very hands-on engineering background, we decided to build an artifact as a way to lead our understanding into the details. We built a small (for its day!) handheld device, not unlike today's PDAs. As we considered the implications of this new world, we encountered serious issues with the underlying tools we were using to build the software:

  • Heterogeneity was a fact of life. The consumer world has many different CPU and system architectures. In the desktop world, these differences ("WinTel" versus Macintosh) partition the market based on low-level details that most people know little about. In the consumer/embedded world, there are many more architectures than the two of the desktop world. The fragmented chaos that would ensue would cause serious problems. Heterogeneity becomes an even more urgent issue when these devices are connected in a network and then start sharing software.

  • Reliability is a huge issue. Non-technophiles have a justifiably low tolerance for systems that malfunction. There are a number of areas where low-level issues in the programming language design (memory integrity being one) have a large impact.

  • Security must be addressed. There is no bigger threat to a network than a "teenage guy" out to have fun. (I know, I was one!) Security is not something that can be painted on afterwards—it has to be built in from the beginning.

  • Consumer devices have a long life span. They live within a world that evolves. This drives a lot of issues in system construction, versioning, and modularity.

  • These systems were becoming distributed and needed to run on more than one machine. They needed to span many machines that would work together to provide a cohesive experience—from small systems such as cell phones, at the edge of the network, to large systems such as the switches that connect them.

These pressures came together and caused a problem. My job on the project was to tackle this, and the result was the Java programming language. The early implementations were targeted at low-end devices.

We released the language to the world in 1995, and it experienced phenomenal popularity. One of the side effects of that popularity was that it quickly moved upscale and was very heavily used in large industrial-strength applications. The smaller-scale fringes of the network got left behind in the enthusiasm.

J2ME brings the technology back to its roots. Programming for these smaller devices can be much more challenging than for large-scale systems because of the constraints in size and speed, but it is generally more rewarding because they have a more personal interaction with their users.

With this book you will learn how J2ME is applied in the wireless world. Wireless applications are a major milestone in making this technology accessible to a much wider community of software developers. The most important opportunities are those that are unexpected, that come from curious people experimenting.

Read. Enjoy. Join in the fun.

James Gosling
Mountain View, California, USA


Preface

In the past five years, Sun has collaborated with major consumer device manufacturers and other companies to create a highly portable, secure, small-footprint Java™ application development environment for resource-constrained, wireless consumer devices such as cellular telephones, two-way pagers, and personal organizers. This work started with the development of a new, small-footprint Java virtual machine called the K Virtual Machine (KVM). Two Java Community Process (JCP) standardization efforts, Connected, Limited Device Configuration (CLDC) and Mobile Information Device Profile (MIDP), were then carried out to standardize the Java libraries and the associated Java language and virtual machine features across a wide variety of consumer devices.

The first round of the CLDC and MIDP standardization efforts took place during the fall of 1999 and spring of 2000. Twenty-four companies participated in the CLDC 1.0 and MIDP 1.0 standardization efforts directly, and more than five hundred companies and individuals participated indirectly by sending feedback while the standardization efforts were in progress. Major consumer device companies such as Motorola, Nokia, NTT DoCoMo, Palm Computing, Research In Motion (RIM), and Siemens played a key role in these efforts.

After their first release, the CLDC 1.0 and MIDP 1.0 standards have become very popular. The deployment of real-world, Java-enabled wireless devices began in 2000, and the deployments accelerated rapidly in 2001 and 2002, approaching exponential growth. It has been estimated that over 50 million devices supporting the CLDC and MIDP standards were shipped in 2002, and the number is likely to be at least twice as large in 2003. As a result of the widespread acceptance of these standards, major business opportunities are now emerging for Java application developers in the wireless device space.

The second round of the CLDC and MIDP standardization efforts was started in the fall of 2001. The goal of the CLDC 1.1 and MIDP 2.0 efforts was to expand on the success of the original standards, refine the existing feature set, and introduce additional APIs, while keeping a close eye on the strict memory limitations that still constrain the design of wireless devices. More than 60 companies were directly involved in the development of the CLDC 1.1 and MIDP 2.0 specifications, reflecting the broad acceptance and adoption of these standards in the wireless industry.

This book intends to make the results of the standardization work in the wireless Java technology area available to the wider software development community. At the high level, this book combines two Java Community Process Specifications, CLDC 1.1 (JSR 139) and MIDP 2.0 (JSR 118), and presents them as a single monograph in a way that the corresponding Java Community Process (JCP) Specifications cannot accomplish by themselves. We have added a general introduction to the Java 2 Platform, Micro Edition (J2ME™), provided more background material, and included a number of small applications to illustrate the use of CLDC and MIDP in the real world. We also provide some guidelines and instructions for getting started with Java 2 Platform, Micro Edition.

A reference implementation of the software discussed in this book is available from Sun Microsystems under the Sun Community Source License (SCSL).


Intended Audience

The book is intended for software developers, content providers, and other professionals who want to develop Java™ software for resource-constrained, connected devices. The book is also targeted to consumer device manufacturers who want to build small Java Powered™ devices and would like to integrate a compact Java application development platform in their products.


Objectives of This Book

This book is the definitive statement, "from the source," about the key specifications for Java Powered™ wireless devices. As such, this book intends to

  • provide an overview of Java™ 2 Platform, Micro Edition (J2ME™),

  • provide a general introduction to the application development platforms defined by the J2ME standardization efforts,

  • explain the technical aspects of the J2ME Connected, Limited Device Configuration version 1.1 (CLDC 1.1),

  • explain the technical aspects of the J2ME Mobile Information Device Profile version 2.0 (MIDP 2.0),

  • provide sample programs to illustrate the use of CLDC and MIDP, and

  • help you get started in writing your own J2ME applications.


How This Book Is Organized

The topics in this book are organized as follows:

  • Chapter 1, "Introduction," provides a context for Java 2 Micro Edition and the CLDC and MIDP specifications.

  • Chapter 2, "Overview of Java 2 Platform, Micro Edition (J2ME™)," provides an overview of Java 2 Micro Edition, its key concepts and components.

  • Chapter 3, "Goals, Requirements, and Scope," defines the goals, requirements, and scope of the CLDC and MIDP standardization efforts.

  • Chapter 4, "Connected Limited Device Configuration," introduces the CLDC standardization effort and summarizes the supported Java programming language and virtual machine features compared to the Java 2 Platform, Standard Edition.

  • Chapter 5, "CLDC Libraries," introduces the Java class libraries defined by the CLDC Specification.

  • Chapter 6, "Mobile Information Device Profile," introduces the MIDP standardization effort.

  • Chapter 7, "MIDP Application Model," introduces the MIDlet application model defined by the MIDP Specification.

  • Chapter 8, "MIDP User Interface Libraries," introduces the user interface libraries defined by the MIDP Specification.

  • Chapter 9, "MIDP High-Level User Interface – Screen," introduces the part of the MIDP high-level user interface revolving around the Screen class.

  • Chapter 10, "MIDP High-Level User Interface – Form," introduces the part of the MIDP high-level user interface revolving around the Form class.

  • Chapter 11, "MIDP Low-Level User Interface Libraries," introduces the low-level user interface libraries defined by the MIDP Specification.

  • Chapter 12, "MIDP Game API," introduces the game API defined by the MIDP Specification.

  • Chapter 13, "MIDP Sound API," introduces the sound API defined by the MIDP Specification.

  • Chapter 14, "MIDP Persistence Libraries," introduces the record management system (RMS) defined by the MIDP Specification.

  • Chapter 15, "MIDP Networking and Serial Communications," introduces the libraries for networking and serial communications defined by the MIDP Specification.

  • Chapter 16, "Secure Networking," introduces the protocols for secure networking defined by the MIDP Specification.

  • Chapter 17, "Event-Driven Application Launch," introduces the protocols for launching MIDlets defined by the MIDP Specification.

  • Chapter 18, "Security for MIDlet Suites," introduces the security protocols for MIDlet suites defined by the MIDP Specification.

  • Chapter 19, "MIDlet Deployment," introduces the mechanisms for transferring a MIDlet to a wireless device.

  • Chapter 20, "Additional MIDP APIs," introduces some additional MIDP application programming interfaces (APIs), such as Timers.

  • Chapter 21, "Summary," summarizes the messages of this book.

  • "References" provides bibliographic references.

  • Appendix A, "CLDC Application Programming Interface," contains the application programming interface documentation in Almanac format for CLDC.

  • Appendix B, "MIDP Application Programming Interface," contains the application programming interface documentation in Almanac format for MIDP.


Related Literature and Helpful Web Pages

The Java™ Language Specification, Second Edition, by James Gosling, Bill Joy, Guy Steele and Gilad Bracha. Addison-Wesley, 2000, ISBN 0-201-31008-2

The Java™ Virtual Machine Specification, Second Edition, by Tim Lindholm and Frank Yellin. Addison-Wesley, 1999, ISBN 0-201-43294-3

Programming Wireless Devices with the Java 2 Platform, Micro Edition, First Edition, by Roger Riggs, Antero Taivalsaari, and Mark VandenBrink. Addison-Wesley, 2001, ISBN 0-201-74627-1

MIDP 2.0 Style Guide by Cynthia Bloch and Annette Wagner. Addison-Wesley, 2003, ISBN 0-321-19801-8

Connected, Limited Device Configuration Specification, version 1.0 http://jcp.org/en/jsr/detail?id=30

Connected, Limited Device Configuration Specification, version 1.1 http://jcp.org/en/jsr/detail?id=139

Mobile Information Device Profile Specification, version 1.0 http://jcp.org/en/jsr/detail?id=37

Mobile Information Device Profile Specification, version 2.0 http://jcp.org/en/jsr/detail?id=118

Java 2 Micro Edition Product Web Page http://java.sun.com/products/j2me/

Connected, Limited Device Configuration (CLDC) Product Web Page http://java.sun.com/products/cldc/

Mobile Information Device Profile (MIDP) Product Web Page http://java.sun.com/products/midp/

J2ME Wireless Toolkit Product Web Page http://java.sun.com/products/j2mewtoolkit/

Web Pages for This Book

Addison-Wesley Page

www.awprofessional.com/titles/0321197984

Sun Microsystems Page

http://java.sun.com/docs/books/j2mewireless-2ndEd/index.html


Acknowledgments

Like most books, this book represents the work of many people. In this case, however, an unusually large number of people around the world have worked to make the Java 2 Platform, Micro Edition—and also this book—a reality. In five short years, a humble, two-person research project at Sun Labs grew rapidly into a highly collaborative product development and standardization effort involving hundreds of companies and thousands of people all over the world. The summary that follows is an attempt to give a glimpse into the different groups of people who participated in this journey. To these and many others too numerous to mention, we give our thanks and appreciation for what they did to make these ideas and this book possible. Attempting to name these people in no way diminishes the contributions of those who we also meant to name but in the pressure of time and the failure of memory somehow overlooked.

Many people read draft versions of this book and sent us comments that improved the book substantially. The authors would like to thank all the reviewers for their willingness to send comments and constructive criticism on the various versions of the book and the sample applications. The authors would also like to thank Lisa Friendly for allowing us to publish this book in Sun's Java book series and for lending us capable technical writing resources to finish this book. Jim Holliday, our technical writer and editor at Sun Microsystems, edited various versions of this book tirelessly. Without his expertise in the mysteries of desktop publishing, grammar, and that pesky topic known as punctuation, this work would have been much worse for the wear. Three other people at Sun Microsystems deserve special mention: Cindy Bloch, Senior Technical Writer, who contributed greatly in editing several chapters; Tasneem Sayeed, Staff Engineer, who provided very detailed comments on the various versions of the book; and Tim Dunn, Visual Designer, who devoted many long hours to perfecting the graphics in this book.

Numerous companies have been involved in the standardization efforts related to the Java 2 Platform, Micro Edition. We would like to thank all the CLDC and MIDP expert group members for their active participation and valuable contributions. In addition to the official members of the CLDC and MIDP expert groups, hundreds of other companies and individuals sent us feedback while the CLDC and MIDP standardization efforts were in progress. The authors found it amazing how much of their time people were willing to contribute to ensure the progress of the Java technology in the wireless space.

Someone once said that hardware without software is a space heater. Similarly, without products, the CLDC and MIDP specifications would be limited in their value. The authors would like to thank wireless device manufacturers, wireless network operators, and software developers for widely embracing the CLDC and MIDP standards, thereby allowing software developers all over the world to finally have a common platform for mobile software development.

Various product groups in Sun's Consumer and Mobile Systems Group (CMSG) organization participated in the design and implementation of the CLDC and MIDP reference implementations. The authors would like to thank Sun's CLDC team, MIDP team, and Wireless Toolkit team members who worked on the reference implementations of the standards and products discussed in this book. The TCK (Technology Compatibility Kit) and Quality Assurance teams at CMSG also played a critical role in ensuring the quality and compatibility of the products.

The Nokia authors would like to thank the following Nokia people who have been closely involved in the MIDP 2.0 standardization work: Kari Systä, Kimmo Löytänä, Markku Tamski, Anna Zhuang, and Antti Rantalahti. Special thanks go to all the Nokia Java teams who have made it possible for Nokia to launch over 30 products with J2ME support and to ship tens of millions of J2ME devices.

The Motorola authors would like to thank all the people in Motorola who helped make CLDC and MIDP a success. Special thanks go to the team members in Motorola's WSAS and iDEN groups that had the vision, developed the first CLDC/MIDP device to reach the market, and still continue to push the envelope in terms of performance and capabilities.

The preparation of this book has been a rather challenging endeavor. The authors are located in different cities and time zones, and because of the extensive amount of travel involved in standardization and product development work these days, a significant portion of the text in this book was written in airplanes, airports, and hotels. Luckily, the advances in wireless technology have made it easier for people to stay in touch regardless of their physical location. Unfortunately, it also means that it is increasingly difficult to avoid those after-8-p.m. phone calls and urgent text messages and e-mails, especially from your co-authors and colleagues located in Western time zones. The standards discussed in this book, for better or worse, will probably only accelerate this trend.

All the authors would like to thank their family and friends who have had the patience and understanding to endure the long hours the authors have spent away from home writing this book, as well as developing these standards and related technologies and products. Without their support and understanding, none of this would have been possible.

Jyri Huopaniemi, Helsinki, Finland
Mark Patel, Chicago, Illinois, USA
Roger Riggs, Burlington, Massachusetts, USA
Antero Taivalsaari, Tampere, Finland
Aleksi Uotila, Tampere, Finland
Jim Van Peursem, Chicago, Illinois, USA

April 2003


Chapter 1. Introduction

    Section 1.1. The Wireless Internet Revolution

    Section 1.2. Why Java™ Technology for Wireless Devices?

    Section 1.3. A Bit of History

    Section 1.4. J2ME™ Standardization Efforts


1.1 The Wireless Internet Revolution

The wireless communications industry has seen rapid growth in the past several years. This has made wireless communication one of the fastest growing technology areas in the world. The total number of cellular phone subscribers worldwide exceeded one billion in 2002, and it has been estimated that there will be over 1.5 billion wireless subscribers in the world by 2005. This far exceeds the number of personal computer users in the world, which was estimated to be about 500 million in 2002. The total annual sales of cell phones in the world is expected to grow from about 423 million phones sold in 2002 to nearly 600 million phones sold in 2006.

At the same time, the rapid emergence of the Internet has changed the landscape of modern computing. People have become more and more dependent on the information that is available on the Internet, and they will increasingly want to access the Internet not only from their personal computers and office workstations but also from mobile, wireless devices. Consequently, the rapid and efficient deployment of new wireless data and mobile Internet services has become a high priority for communication equipment manufacturers and telecommunication operators.

The transition to wireless, mobile Internet devices will fundamentally alter the landscape and architecture of communication networks, devices, and services. Unlike in the past, when wireless devices typically came from the factory with a hard-coded feature set, the devices will become more and more customizable. The possibility to download new applications and features over wireless networks will open up completely new possibilities for device manufacturers, network operators, service and content providers, and device users themselves.

The wireless Internet revolution will be facilitated by another important technological advance: the introduction of broadband third- and fourth-generation wireless networks. While current wireless networks have limited data rates, allowing the users to transfer only up to a few tens of kilobits of data per second, broadband wireless networks will provide data rates ranging from hundreds of kilobits up to several megabits per second. This will provide enough bandwidth to transfer photographs, live video, and high-quality audio, as well as to download significantly larger applications and services than today.

All these changes will happen relatively fast. Even though it will still take a few years before broadband wireless networks are in widespread use, it is safe to estimate that the majority of new wireless devices will have high-speed connectivity to the Internet by the end of the decade.


1.2 Why Java™ Technology for Wireless Devices?

The wireless Internet revolution will transform wireless devices from voice-oriented communication devices with relatively static, hard-coded functionality into extensible, Internet-enabled devices with advanced data and software capabilities. These devices will need to support dynamic downloading of new software and be capable of running software written not only by the device manufacturers themselves but also by third-party software developers. This will make the devices much more dependent on software and will place a much higher emphasis on software interoperability, security, and reliability.

The Java™ programming language is ideally suited to become the standard application development language for wireless devices. After all, the Java platform provides a number of important benefits:

  • Dynamic delivery of content. New applications, services, and content can be downloaded dynamically over different kinds of networks.

  • Security. Class file verification, well-defined application programming interfaces, and security features ensure that third-party applications behave reliably and cannot harm the devices or the networks.

  • Cross-platform compatibility. Standardized language features and libraries mean that applications and content can be transferred flexibly between different devices, within constraints of the supported J2ME™ configuration and profiles (see Section 2.3, "Key Concepts of the J2ME Architecture," for details).

  • Enhanced user experience and interactive content. The standards defined for wireless Java technology support sophisticated user interaction and provide compelling graphics capabilities for small devices.

  • Offline access. Applications can also be used without active network connection. This reduces transport costs and alleviates the impact of possible network failures.

  • The power of a modern object-oriented programming language. The Java programming language has far better abstraction mechanisms and higher-level programming constructs than other languages and tools that are currently used for wireless software development, allowing applications to be developed more efficiently.

  • Large developer community. It is estimated that there are more than three million Java software developers worldwide. The Java programming language is rapidly becoming the most popular programming language taught in schools and universities. The developer talent needed for Java software development already exists and is readily available.

Ultimately, Java technology will deliver far more compelling, entertaining, and engaging capabilities to wireless devices. What is particularly important is that this can be accomplished incrementally, by complementing existing technologies and standards, rather than by competing with them. One of the key points we emphasize throughout this book is that we are not defining a new operating system or a complete system software stack for wireless devices. Rather, the goal of this work is to define and standardize a portable wireless application development environment that targets primarily third-party application developers and will open the devices for third-party software development. This environment can be added flexibly on top of the existing software and hardware solutions that the device manufacturers already have. Typically, the changes required to the existing system software are very small. For more information, see Section 3.1, "High-Level Goals."


1.3 A Bit of History

The Java programming language was initially targeted towards consumer devices, especially the interactive TV market. However, over time the Java platform evolved more and more towards the needs of desktop and enterprise computing. Enterprise applications generally require rich library functionality, and over time the Java libraries grew larger and more comprehensive to cater better to the needs of the enterprise market and large server-side applications. However, this evolution made the libraries too large and unsuitable for the majority of small, resource-constrained devices.

In January 1998, the Spotless project was started at Sun Microsystems Laboratories (Sun Labs) to investigate the use of the Java programming language in extremely resource-constrained devices. The research goal of the project was to build a Java runtime environment that would fit in less than one-tenth of the typical size. At the implementation level, the goal was to build a Java virtual machine with the following characteristics:

  • small size

  • portability

  • ease of use and readability of the source code

Small size is important, since the majority of wireless, mobile devices (for example, cell phones) are still very resource-limited and often have only a few tens or hundreds of kilobytes of memory available for applications. Portability, ease of use, and the readability of the source code are equally important. Most embedded device manufacturers need to support dozens or even hundreds of different hardware configurations that run on several different hardware platforms, and it would be not only tedious but also very expensive to spend a lot of time porting and customizing the Java platform implementation to all those hardware configurations and platforms. Also, embedded device manufacturers cannot generally be expected to be experts on the Java programming language or virtual machine. Therefore, the easier the implementation is to understand and use, the faster the device manufacturers will deploy it across their devices.

Even though the Spotless effort was initially a research project, the project group established active contacts with external customers early on. External customers, especially Motorola, played a significant role in convincing Sun to turn the Spotless system from a research project into a commercial product. The product version of the Spotless virtual machine is known today as the K Virtual Machine (KVM). The Spotless system is documented in the Sun Labs technical report The Spotless System: Implementing a Java System for the Palm Connected Organizer (Sun Labs Technical Report SMLI TR-99-73).


1.4 J2ME™ Standardization Efforts

Once Motorola, Nokia, NTT DoCoMo, Palm Computing, RIM, Siemens, and other device manufacturers became interested in the KVM development effort, standardization was necessary in order to guarantee interoperability between the different kinds of Java Powered™ devices from different manufacturers. Two Java Community Process (JCP) standardization efforts were launched in the fall of 1999.

The first of these standardization efforts, Connected, Limited Device Configuration (CLDC), was launched on October 1, 1999. The goal of this effort was to define the "lowest common denominator" Java platform for a wide variety of small, connected, resource-constrained devices. This specification defines the minimum required complement of Java technology components and libraries for small devices. Java programming language and virtual machine features, core libraries, input/output, networking, and security are the primary topics addressed by the CLDC Specification. The CLDC standard does not target any specific device category. Rather, it defines a general-purpose building block on top of which more device category specific profiles are defined. Eighteen companies participated in the CLDC 1.0 (JSR 30) expert group work.

The second standardization effort, Mobile Information Device Profile (MIDP), was started in November 1999. That effort was based on the platform defined by the CLDC effort, adding features and APIs that focus specifically on two-way wireless communication devices such as cell phones and two-way pagers. Application model, user interface, networking, and storage APIs are the primary focus areas of the MIDP Specification. Twenty-two companies participated in the MIDP 1.0 (JSR 37) expert group work.

After becoming widely accepted in the marketplace, second-generation CLDC and MIDP standardization efforts were launched in the fall of 2001.

The CLDC 1.1 (JSR 139) effort was started in September 2001. CLDC 1.1 adds a number of features that improve the compatibility of the J2ME platform with the full Java 2 Platform, Standard Edition (J2SE™). The most significant new feature added in CLDC 1.1 is floating point support, but there are a number of other important features as well. The CLDC standardization effort is described in more detail in Chapter 4, "Connected Limited Device Configuration," and Chapter 5, "CLDC Libraries."

The MIDP 2.0 (JSR 118) effort was started in August 2001. MIDP 2.0 adds a number of important new libraries such as a Sound API and a Game API, as well as provides important refinements and extensions to the existing MIDP APIs. The MIDP standardization effort is discussed in Chapter 6, "Mobile Information Device Profile" and subsequent chapters.

The general framework for CLDC and MIDP, as well as other Java technology standardization efforts in the small device space, is known as Java™ 2 Platform, Micro Edition (J2ME) or simply Java 2 Micro Edition. An introduction to Java 2 Micro Edition is provided in the next chapter.

In addition to the CLDC and MIDP standardization efforts, there are a large number of additional J2ME standardization efforts that build upon these core standards. A summary of the J2ME optional packages created by the additional standardization efforts will be provided in Section 2.4, "Evolution of the J2ME Platform."


Chapter 2. Overview of Java 2 Platform, Micro Edition (J2ME™)

    Section 2.1. Java 2 Platform

    Section 2.2. Java 2 Platform, Micro Edition (J2ME)

    Section 2.3. Key Concepts of the J2ME Architecture

    Section 2.4. Evolution of the J2ME Platform


2.1 Java 2 Platform

Recognizing that one size does not fit all, Sun Microsystems has grouped Java technologies into three editions, each aimed at a specific area of today's vast computing industry:

  • Java 2 Platform, Enterprise Edition (J2EE™) for enterprises needing to serve their customers, suppliers, and employees with scalable server solutions.

  • Java 2 Platform, Standard Edition (J2SE™) for the familiar and well-established desktop computer market.

  • Java 2 Platform, Micro Edition (J2ME™) for the combined needs of:

    • consumer and embedded device manufacturers who build a diversity of information devices,

    • service providers who wish to deliver content to their customers over those devices, and

    • content creators who want to make compelling content for small, resource-constrained devices.

Each Java platform edition defines a set of technologies that can be used with a particular product:

  • Java Virtual Machines that fit inside a wide range of computing devices,

  • libraries and APIs specialized for each kind of computing device, and

  • tools for deployment and device configuration.

Figure 2.1 illustrates the Java 2 Platform editions and their target markets, starting from the high-end platforms on the left and moving towards low-end platforms on the right. Basically, five target markets or broad device categories are identified. Servers and enterprise computers are supported by Java 2 Enterprise Edition, and desktop and personal computers by Java 2 Standard Edition. Java 2 Micro Edition is divided broadly into two categories that focus on "high-end" and "low-end" consumer devices. Java 2 Micro Edition is discussed in more detail later in this chapter. Finally, the Java Card™ standard focuses on the smart card market.

Figure 2.1. Java 2 Platform editions and their target markets

    [ Team LiB ]


2.2 Java 2 Platform, Micro Edition (J2ME)

Java™ 2 Platform, Micro Edition (henceforth referred to as Java 2 Micro Edition or J2ME) specifically addresses the large, rapidly growing consumer space, which covers a range of devices from tiny commodities, such as pagers, all the way up to the TV set-top box, an appliance almost as powerful as a desktop computer. Like the larger Java editions, Java 2 Micro Edition aims to maintain the qualities that Java technology has become known for, including built-in consistency across products, portability of code, safe network delivery, and upward scalability.

The high-level idea behind J2ME is to provide comprehensive application development platforms for creating dynamically extensible, networked devices and applications for the consumer and embedded market. J2ME enables device manufacturers, service providers, and content creators to capitalize on new market opportunities by developing and deploying compelling new applications and services to their customers worldwide. Furthermore, J2ME allows device manufacturers to open up their devices for widespread third-party application development and dynamically downloaded content without losing the security or the control of the underlying manufacturer-specific platform.

At a high level, J2ME is targeted at two broad categories of products:

  • "High-end" consumer devices. In Figure 2.1, this category is represented by the grouping labeled CDC (Connected Device Configuration). Typical examples of devices in this category include TV set-top boxes, Internet TVs, Internet-enabled screenphones, high-end wireless communicators, and automobile entertainment/navigation systems. These devices have a large range of user interface capabilities, total memory budgets starting from about two to four megabytes, and persistent, high-bandwidth network connections, often using TCP/IP.

  • "Low-end" consumer devices. In Figure 2.1, this category is represented by the grouping labeled CLDC (Connected, Limited Device Configuration). Cell phones, pagers, and personal organizers are examples of devices in this category. These devices have simple user interfaces (compared to desktop computer systems), minimum memory budgets starting from about 128–256 kilobytes, and low bandwidth, intermittent network connections. In this category of products, network communication is often not based on the TCP/IP protocol suite. Most of these devices are battery-operated.

The line between these two categories is fuzzy and becoming more so every day. As a result of the ongoing technological convergence in the computer, telecommunication, consumer electronics, and entertainment industries, there will be less technical distinction between general-purpose computers, personal communication devices, consumer electronics devices, and entertainment devices. Also, future devices are more likely to use wireless connectivity instead of traditional fixed or wired networks. In practice, the line between the two categories is defined more by the memory budget, bandwidth considerations, battery power consumption, and physical screen size of the device rather than by its specific functionality or type of connectivity.

Because of strict manufacturing cost constraints, the majority of high-volume wireless devices today, such as cell phones, belong to the low-end consumer device category. Therefore, this book focuses only on the CLDC and MIDP standards that were specifically designed for that category of products.


2.3 Key Concepts of the J2ME Architecture

While connected consumer devices such as cell phones, pagers, personal organizers, and TV set-top boxes have many things in common, they are also extremely diverse in form, function, and features. Information appliances tend to be special-purpose, limited-function devices. To address this diversity, an essential requirement for the J2ME architecture is not only small size but also modularity and customizability.

In general, serving the information appliance market calls for a large measure of flexibility in how computing technology and applications are deployed. This flexibility is required because of

  • the large range of existing device types and hardware configurations,

  • the different usage models employed by the devices (key operated, stylus operated, voice operated),

  • constantly improving device technology,

  • the diverse range of existing applications and features, and

  • the need for applications and capabilities to change and grow, often in unforeseen ways, in order to accommodate the future needs of the consumer.

The J2ME architecture is intended to be modular and scalable so that it can support the kinds of flexible deployment demanded by the consumer and embedded markets. To enable this, the J2ME environment provides a range of Java Virtual Machine technologies, each optimized for the different processor types and memory footprints commonly found in the consumer and embedded marketplace.

For low-end, resource-limited consumer products, the J2ME environment supports minimal configurations of the Java Virtual Machine and Java libraries that embody just the essential capabilities of each kind of device. As device manufacturers develop new features in their devices or service providers develop new and exciting applications, these minimal configurations can be expanded with additional libraries that address the needs of a particular market segment. To support this kind of customizability and extensibility, three essential concepts are defined by the J2ME architecture:

  • Configuration. A J2ME configuration defines a minimum platform for a "horizontal" category or grouping of devices, each with similar requirements on total memory budget and processing power. A configuration defines the Java language and virtual machine features and minimum class libraries that a device manufacturer or a content provider can expect to be available on all devices of the same category.

  • Profile. A J2ME profile is layered on top of (and thus extends) a configuration. A profile addresses the specific demands of a certain "vertical" market segment or device family. The main goal of a profile is to guarantee interoperability within a certain vertical device family or domain by defining a standard Java platform for that market. Profiles typically include class libraries that are far more domain-specific than the class libraries provided in a configuration. One device can support multiple profiles.

  • Optional package. Some APIs are applicable to a large number of devices and device families. A J2ME optional package is a set of APIs that is layered on top of (and thus extends) a profile. An optional package typically contains functionality that is independent of any particular vertical market segment or device family. The main goal of an optional package is to allow the definition of APIs that can be added flexibly on top of a number of different profiles. One device can support multiple optional packages.

Configurations, profiles, and optional packages are discussed in more detail below. Configurations, profiles, and optional packages use the capabilities of the Java Virtual Machine (JVM), which is considered to be part of the configuration. The virtual machine usually runs on top of a host operating system that is part of the system software of the target device. The high-level relationship between the different software layers—the JVM, configuration, profiles, optional packages, and the host operating system—is illustrated in Figure 2.2.

Figure 2.2. Software layers in a J2ME device

J2ME configurations, profiles, and optional packages are defined through industry collaboration using the Java Community Process (JCP). For further information on the Java Community Process, refer to the Java Community Process web site (http://jcp.org/).

2.3.1 Profiles

Application portability is a key benefit of Java technology in the desktop and enterprise server markets. Portability is an equally critical element in the consumer device space. However, application portability requirements in the consumer space are very different from portability requirements demanded by the desktop and server markets. In most cases, consumer devices differ substantially in memory size, networking, and user interface capabilities, making it very difficult to support all devices with just one solution.

In general, the consumer device market is not so homogeneous that end users can expect or require universal application portability. Rather, in the consumer space, applications should ideally be fully portable within the same device family. For example, consider the following types of consumer devices:

  • cellular telephones,

  • washing machines, and

  • electronic toys.

It seems clear that each of these represents a different market segment, device family, or application domain. As such, consumers would expect useful applications to be portable within a device family. For example:

  • A discount broker's stock trading application is generally expected to work on different cell phones, even though the phones are from different manufacturers.

  • It would be annoying if a highly useful grape-juice-stain-removing wash cycle application available on the Internet runs on an old brand-X washer but not a new brand-Z washer.

  • A child's birthday party could be less enjoyable if the new toy robot does not "talk to" or "play games with" the new electronic teddy bear.

On the other hand, consumers do not expect the stock trading application or an automobile service program to run on the washing machine or the toy robot. In other words, application portability across different device categories is not necessarily very important or even meaningful in the consumer device space.

In addition, there are important economic reasons to keep these device families separate. Consumer devices compete heavily on cost and convenience, and these factors often translate directly into limitations on physical size and weight, processor power, memory size, and power consumption (in battery-powered devices). Consumers' wallets will usually favor devices that have the right functionality at the right price. In other words, the devices must perform the desired functions well, but they do not have added cost for unnecessary features.

Thus, the J2ME framework provides the concept of a profile to make it possible to define Java platforms for specific vertical markets. A profile defines a Java platform for a specific vertical market segment or device category. Profiles can serve two distinct portability requirements:

  • A profile provides a complete toolkit for implementing applications for a particular kind of device, such as a pager, set-top box, cell phone, washing machine, or interactive electronic toy.

  • A profile may also be created to support a significant, coherent group of applications that might be hosted on several categories of devices. For example, while the differences between set-top boxes, pagers, cell phones, and washing machines are significant enough to justify creating a separate profile for each, it might be useful for certain kinds of personal information management or home banking applications to be portable to each of these devices. This could be accomplished by creating a separate profile for these kinds of applications and ensuring that this new profile can be easily and effectively supported on each of the target devices along with its "normal" more device-specific profile.

It is possible for a single device to support several profiles. Some of these profiles are very device-specific, while others are more application-specific. Applications are written "for" a specific profile and are required to use only the features defined by that profile. Manufacturers choose which profile(s) to support on each of their devices, but are required to implement all features of the chosen profile(s). The value proposition to the consumer is that any application written for a particular profile will run on any device that supports that profile.

In its simplest terms, a profile is a contract between an application and a vertical market segment. All the devices in the same market segment agree to implement all the features defined in the profile, and the application agrees to use only those features that are defined in the profile. Thus, portability is achieved between the applications and the devices served by that profile. New devices can take advantage of a large and familiar application base. Most importantly, new compelling applications (perhaps completely unforeseen by the original profile designers and device manufacturers) can be dynamically downloaded to existing devices.

At the implementation level, a profile is defined simply as a collection of class libraries that reside on top of a specified configuration and that provide the additional domain-specific capabilities for devices in a specific market segment.

In our example above, each of the three families of devices (cell phones, washing machines, and intercommunicating toys) could be addressed by a separate J2ME profile. The only one of these profiles in existence at the current time is the MIDP, designed for cell phones and other two-way communication devices.

2.3.2 Configurations

In the J2ME environment, an application is written "for" a particular profile, and a profile is "based upon" or "extends" a particular configuration. Thus, all of the features of a configuration are automatically included in the profile and may be used by applications written for that profile.

A configuration defines a Java platform for a "horizontal" category or grouping of devices with similar requirements on total memory budget and other hardware capabilities. More specifically, a configuration:

  • specifies the Java programming language features supported,

  • specifies the Java Virtual Machine features supported, and

  • specifies the basic Java libraries and APIs supported.

The J2ME environment is designed so that it can be deployed in more than one configuration. Each configuration specifies the Java language and virtual machine features and a set of libraries that the profile implementer (and the applications using that profile) can safely assume to be present on all devices when shipped from the factory. Profile implementers must design their code to stay within the bounds of the features and libraries specified by that configuration.

In its simplest terms, a configuration defines a "lowest common denominator" platform or building block for device manufacturers and profile implementers. All the devices with approximately the same amount of memory and processing power agree to implement all the features defined in the configuration, and the profile implementers agree to use only those features defined in the configuration. Thus, portability is achieved between the profile and the devices served by that configuration.

In our example above, each of the three profiles (for cell phones, washing machines, and electronic toys) would most likely be built upon the same configuration, the CLDC. This configuration provides all the basic functionality to serve the needs of each of these, and perhaps many more, profiles.

To avoid fragmentation, there are a very limited number of J2ME configurations. As depicted in Figure 2.1, only two standard J2ME configurations are available:

  • Connected, Limited Device Configuration (CLDC). This configuration focuses on low-end consumer devices. Typical examples of CLDC target devices include personal, mobile, battery-operated, connected information devices such as cell phones, two-way pagers, and personal organizers. This configuration includes some new libraries, not drawn from the J2SE APIs, designed specifically to fit the needs of small-footprint devices.

  • Connected Device Configuration (CDC). This configuration focuses on high-end consumer devices. Typical examples of CDC target devices include shared, connected information devices such as TV set-top boxes, Internet TVs, and high-end communicators. This configuration includes a much more comprehensive set of Java libraries and virtual machine features than CLDC.

Figure 2.3 illustrates the relationship between CLDC, CDC, and Java 2 Standard Edition (J2SE). As shown in the figure, the majority of functionality in CLDC and CDC has been inherited from Java 2 Platform, Standard Edition (J2SE). Each class inherited from the J2SE environment must be precisely the same or a subset of the corresponding class in the J2SE environment. In addition, CLDC and CDC may introduce a number of features, not drawn from the J2SE, designed specifically to fit the needs of small-footprint devices.

Figure 2.3. Relationship between J2ME configurations and Java 2 Standard Edition

The most important reason for the configuration layer in the J2ME environment is that core Java libraries needed across a wide variety of Java platform implementations are usually intimately tied with the implementation of a Java Virtual Machine. Small differences in the specification of a configuration can require a number of significant modifications to the internal design of a Java Virtual Machine and can require a substantial amount of additional memory footprint. Such modifications would be very expensive and time-consuming to maintain. Having a small number of configurations means that a small number of virtual machine implementations can serve the needs of both a large number of profiles and a large number of different device hardware types. This economy of scale provided by the J2ME environment is very important to the success and cost-effectiveness of devices in the consumer and embedded industry.

2.3.3 Optional Packages

Soon after the introduction of the original CLDC and MIDP standards, it was realized that, in addition to configurations and profiles, there is a need for additional, general-purpose libraries that are not bound to a single device category or family. For instance, a location API that provides facilities for geographic positioning is potentially applicable to a broad number of devices and device families, and is not functionally limited only to a single profile. Similarly, a wireless messaging API could potentially be applied to a number of different types of devices and profiles. To address the need to create such broadly applicable, device family independent APIs, the concept of optional packages was added to the architecture of the J2ME platform.

Generally speaking, a J2ME optional package is an API that can be used to extend a profile. An optional package exposes specific functionality independent of any profile and is naturally distinct from any profile. Optional packages provide APIs that are intended for reuse by profile design teams and vendors of J2ME environments.

It is expected that optional packages may sometimes play an important role in the evolution of a profile. As APIs are developed for new technologies and features, the new APIs are initially developed as optional packages. However, as those APIs mature and new versions are created through the Java Community Process, optional packages may later be incorporated into a profile.

A summary of J2ME optional packages created so far for the wireless market is provided in the next section.


2.4 Evolution of the J2ME Platform

After the successful completion of the CLDC and MIDP standardization efforts, a number of additional J2ME standardization efforts have been launched to complement the functionality provided by the core standards. Most of these additional efforts define optional packages that can be deployed on top of MIDP. These efforts are summarized in Section 2.4.2, "Optional Packages for the Wireless Market" below. In addition, there are a number of more fundamental, core standardization efforts that are summarized in Section 2.4.1, "Core J2ME Standardization Efforts."

2.4.1 Core J2ME Standardization Efforts

There are a number of standardization activities that have an important role in defining the overall J2ME architecture. These efforts can be viewed as "umbrella" activities that specify the ground rules for a number of standardization activities or provide additional instructions, recommendations, and clarifications for binding together the existing J2ME standards:

  • JSR 68: J2ME™ Platform Specification

  • JSR 185: Java™ Technology for Wireless Industry

JSR 68: J2ME™ Platform Specification

This specification defines the "ground rules" for the J2ME platform architecture and J2ME standardization activities. It formalizes the fundamental concepts behind J2ME, such as the notions of a configuration and profile, and defines how new J2ME APIs can be formed by subsetting existing APIs from the Java 2 Platform, Standard Edition (J2SE).

JSR 185: Java™ Technology for the Wireless Industry (JTWI)

This specification defines how various technologies associated with MIDP work together to form a complete handset solution for the wireless services industry. The specification provides an exposition of the overall architecture of the wireless client software stack, including a description of the following aspects:

  • Which optional packages fit with which profiles?

  • How does an end-to-end solution for interoperable Java applications work?

  • How does the migration of applications occur, and to which profiles, as the devices become more capable?

A key goal of the JTWI Specification is to minimize the fragmentation of the Java APIs in the mobile handset market by creating a community that coordinates the API evolution and deployment as the industry continues to expand the capabilities of mobile devices. To accomplish this, the JSR 185 expert group coordinates the creation of new J2ME-related JSRs and provides recommendations for new optional packages that could take place within the context of the wireless development community as a whole.

2.4.2 Optional Packages for the Wireless Market

The following standardization efforts define optional packages that can reside on top of MIDP:

  • JSR 120: Wireless Messaging API

  • JSR 135: Mobile Media API

  • JSR 172: J2ME™ Web Services Specification

  • JSR 177: Security and Trust Services for J2ME™

  • JSR 179: Location API for J2ME™

  • JSR 180: Session Initiation Protocol (SIP) for J2ME™

  • JSR 184: Mobile 3D Graphics for J2ME™

  • JSR 190: Event Tracking API for J2ME™

Each of these efforts is summarized briefly below.

JSR 120: Wireless Messaging API

This JSR defines a set of optional APIs that provide standardized access to wireless communication resources, allowing third-party developers to build intelligent connected Java applications. The specification addresses the following wireless technologies:

  • Short Message Service (SMS), and

  • Cell Broadcast Service (CBS).

JSR 135: Mobile Media API (MMAPI)

This JSR specifies a multimedia API for J2ME, providing straightforward access and control of basic audio and multimedia resources and files. The MIDP 2.0 Sound API (introduced in Chapter 13 of this book) is a subset of the Mobile Media API defined by JSR 135.

JSR 172: J2ME™ Web Services Specification

This specification defines an optional package that provides standard access from J2ME devices to Web services. The JSR is designed to provide an infrastructure to

  • provide basic XML processing capabilities,

  • enable reuse of Web service concepts when designing J2ME clients to enterprise services,

  • provide APIs and conventions for programming J2ME clients of enterprise services,

  • adhere to Web service standards and conventions around which the Web services and Java developer community is consolidating,

  • enable interoperability of J2ME clients with Web services, and

  • provide a programming model for J2ME client communication with Web services, consistent with that for other Java clients such as J2SE.

JSR 177: Security and Trust Services API for J2ME™

The purpose of this JSR is to define a collection of APIs that provide security services to J2ME devices. These APIs are a necessary step for a device to become trusted, that is, to provide security mechanisms to support a wide variety of application-based services, such as access to corporate network, mobile commerce, and digital rights management.

Many of these services rely on the interaction with a "security element" (such as a smart card) in the device for secure storage and execution, as described below:

  • Secure storage to protect sensitive data, such as the user's private keys, public key (root) certificates, service credentials, personal information, and so on.

  • Secure execution, such as cryptographic operations to support payment protocols, data integrity, and data confidentiality.

  • Custom and enabling security features that J2ME applications can rely on to handle many valued-added services, such as user identification and authentication, banking, payment, ticketing, loyalty applications, and digital media playing.

The JSR 177 specification defines an access model and a set of APIs that enable applications running on a J2ME device to communicate with a smart card inserted in the device, providing a flexible mechanism to allow service and equipment providers to define secure operations.

JSR 179: Location API for J2ME™

This specification defines an optional package that enables developers to write mobile, location-based applications for J2ME devices. The purpose of the specification is to provide a compact and generic API that produces information about the device's present physical location to Java applications. This specification defines a generic interface that works with most positioning methods, such as GPS and E-OTD.

JSR 180: Session Initiation Protocol (SIP) for J2ME™

The Session Initiation Protocol (SIP) is used to establish and manage multimedia IP sessions. This same mechanism can also be used to provide instant messaging, presence, and gaming services. This specification defines a general SIP API for J2ME devices based on the SIP protocol defined by IETF and 3GPP, and targeting resource constrained platforms.

JSR 184: Mobile 3D Graphics API for J2ME™

This specification defines a lightweight, interactive 3D graphics API, which sits alongside J2ME and MIDP as an optional package. The API is targeted at devices that typically have very little processing power and memory, and no hardware support for 3D graphics or floating point math. However, the API also scales up to higher-end devices that have a color display, a DSP, a floating point unit, or even specialized 3D graphics hardware. The API is designed to make rapid development of compelling 3D applications feasible and is intended to be flexible enough for a wide range of applications, including games, animated messages, screen savers, custom user interfaces, product visualization, and so on.

JSR 190: Event Tracking API for J2ME™

This specification defines an optional package that standardizes the tracking of application events in a mobile device and the submission of these event records to an event-tracking server via a standard protocol. The events can be used for purposes such as billing, usage tracking, application revocation, update notification, reviews and ratings, and so on.

The Event Tracking API is intended to work with devices supporting CLDC 1.0 and later. The API is designed as an optional package that can be used with many J2ME profiles, in particular MIDP 1.0 and MIDP 2.0.

For More Information

For additional information on each effort mentioned above, refer to corresponding pages on the Java Community Process web site (http://jcp.org).


Chapter 3. Goals, Requirements, and Scope

The CLDC and MIDP standards intend to bring the benefits of Java technology to resource-constrained wireless devices with limited Internet connectivity. This chapter reviews the goals, requirements, and scope of these standards.


3.1 High-Level Goals

The general goal of the J2ME standardization efforts discussed in this book is to define a highly portable, secure, small-footprint application development environment for resource-constrained, connected devices. We emphasize the term application development environment. The CLDC and MIDP standards are not intended to replace existing system software stacks or to serve as a complete operating system for small devices. Rather, the goal of these efforts is to define an environment that can be added flexibly on top of an existing system software stack to support third-party application development and secure, dynamic downloading of applications.

The CLDC and MIDP standardization efforts have slightly different but complementary goals. Connected, Limited Device Configuration is intended to serve as a generic, "lowest common denominator" platform that targets all kinds of small, connected devices—independent of any specific device category. Mobile Information Device Profile builds on top of CLDC and focuses on a specific category of devices: wireless, mobile, two-way communication devices such as cellular telephones and two-way pagers.

3.1.1 Dynamic Delivery of Java Applications and Content

One of the greatest benefits of Java technology in the small device space is the dynamic, secure delivery of interactive services and applications over different kinds of networks. Unlike in the past, when small devices such as cell phones and pagers came from the manufacturer with a hard-coded feature set, device manufacturers are increasingly looking for solutions that allow them to build extensible, customizable devices that support rich, dynamic, interactive content from third-party content providers and developers. With the recent introduction of Internet-enabled cell phones, communicators, and pagers, this transition is already under way. Several wireless device manufacturers are already offering cell phones that allow users to download new applications such as interactive games, screen savers, banking and ticketing applications, wireless collaboration tools, and so on (Figure 3.1).

Figure 3.1. Downloading customized services

Note that such customizability is not necessarily limited to communication devices such as cell phones or two-way pagers. For instance, it is quite possible to envision automobile engines that obtain new service programs and updates as they become available, washing machines that download new washing programs dynamically, electronic toys that automatically download updated game programs, and so on. The range of possible applications is virtually endless.

One of the main goals of both the Connected, Limited Device Configuration and Mobile Information Device Profile is to take this transition several steps further by allowing the use of the Java programming language as the standard platform for the secure delivery of dynamic content for these extensible next-generation devices.

3.1.2 Third-Party Application Development

The focus on dynamically delivered applications means that CLDC and MIDP are intended not only for hardware manufacturers and their system programmers but also for third-party application developers. In fact, we assume that once Java Powered™ small devices become commonplace, the vast majority of application developers for these devices will be third-party developers rather than device manufacturers.

This focus on third-party application development has some important implications for the features and libraries included in the CLDC and MIDP standards. First, the CLDC and MIDP specifications include only high-level libraries that provide sufficient programming power for the third-party application developer. For instance, the networking APIs included in MIDP provide the programmer with meaningful high-level abstractions, such as the ability to transfer entire files or web pages at once, rather than require the programmer to know about the details of specific network transmission protocols. Second, we emphasize the importance of generality, portability, and interoperability. The CLDC and MIDP specifications are intended to support a wide range of devices and do not focus on any specific single type or brand of devices.

3.1.3 Independence of Network Technology Standards

The wireless communications industry has never suffered from the lack of technology standards. There is a plethora of wireless technologies in use all over the world, with varying levels of sophistication, compatibility, and interoperability. The second-generation (2G) digital wireless network technologies include standards such as GSM, TDMA, CDMA, and PDC. Third-generation (3G) wireless network technology standards include WCDMA, CDMA2000, and TD-SCDMA. In addition, there are several second-and-a-half-generation (2.5G) standards such as GPRS, CDPD, and EDGE.

One of the key goals for J2ME standardization efforts is to define solutions that can work effectively with all these network technologies and standards. Any APIs or features that would focus only on one specific type of network technology are generally avoided. An additional goal in the CLDC and MIDP standardization work was to ensure that the solutions can be used both in today's relatively low-speed wireless networks and in tomorrow's high-speed broadband wireless networks.

To reach the goals just mentioned, the CLDC standard defines a special Generic Connection framework for supporting networking in a coherent, extensible fashion. This is discussed in detail in Section 5.3.2, "The Generic Connection Framework." The MIDP standard utilizes the Generic Connection framework and defines a number of concrete network protocols that are guaranteed to be available in all devices supporting MIDP.

3.1.4 Compatibility with Other Wireless Application Standards

A key goal for the standards defined in this book is to provide interoperability with existing and forthcoming wireless application development standards and technology stacks such as Open Mobile Architecture[1] (OMA) and i-Mode. This means that the application development environments defined by CLDC and MIDP can complement existing technologies rather than compete with them. For instance, today's wireless devices already commonly provide a simple microbrowser for finding services on the Internet. This microbrowser can be extended to locate and launch Java applications as well. A microbrowser augmented with Java application execution capabilities will provide better user interaction and graphics capabilities, support offline use of applications, and make the development of compelling applications generally much easier.

[1] Defined by Open Mobile Alliance (http://www.openmobilealliance.org/).


3.2 Target Devices

Potential target devices for the Mobile Information Device Profile (MIDP) include two-way communication devices such as cellular telephones, two-way pagers, and wireless personal organizers. The Connected, Limited Device Configuration (CLDC) can additionally be used to support other kinds of devices such as point-of-sale terminals, barcode scanners, inventory control devices, audio/video equipment, home appliances, and device controllers (for routers, sensors, vending machines, engines, and so forth). In general, CLDC is intended to be applicable to any resource-constrained device that might benefit from a portable, low-cost application development environment that supports secure, dynamic downloading of third-party applications.[2]

[2] Note that CLDC defines only general-purpose APIs, so additional APIs and/or J2ME profiles are typically necessary to address the specific needs of each device category.

The characteristics of the CLDC and MIDP target devices are summarized in Figure 3.2. The technical hardware and software requirements of CLDC and MIDP target devices are defined in detail later in this chapter.

Figure 3.2. CLDC and MIDP target devices

The user interaction models of CLDC and MIDP target devices vary significantly. Consider, for example, how a user interacts with today's crop of mobile information devices.

The most common example is that of "one-handed" operation. Devices of this type are typical cellular phones with small LCD displays and a standard ITU-T telephone keypad (containing at least the keys 0–9, *, and #). Users interact with this type of device with one hand, usually with their thumb only. With devices of this type, smaller is better, so these devices typically have a very limited display.

Other mobile information devices are operated in "two-handed mode." These devices have a small, conventional "QWERTY" keyboard. Data entry for these devices is much like using a PC, although due to the small size, touch typing can be problematic; consequently, many devices in this category are operated by two thumbs rather than ten fingers. Given that a QWERTY keyboard takes up more space than a telephone keypad, the display in these devices is usually larger than that found in a normal cellular phone.

As a final example of user interaction models, consider a device that depends on a touch screen. These devices primarily interact with the user by having a simple, consistent, and well-designed menu system. In addition, these devices might depend on handwriting recognition or a virtual keyboard for user-input text. Given that text input is commonly done via a stylus, these devices typically have larger LCD screens—in fact, often much larger than the other two types of devices discussed.

Both CLDC and MIDP are designed to cater to all the different usage models presented in Figure 3.3, and consequently the CLDC and MIDP specifications make minimal assumptions about user interaction models of the target devices.

Figure 3.3. One-handed, two-handed, and stylus-operated mobile information devices

    [ Team LiB ]


3.3 General Notes on Consumer Devices and Embedded Systems

Over the past thirty years, the performance of computer hardware has doubled approximately every 12 to 24 months. This has led to unprecedented miniaturization and widespread usage of computer technology. The price of the microprocessor in today's personal computers is only a few cents per megahertz, and the price is still decreasing rapidly. Today's small wireless devices such as cell phones and two-way pagers have microprocessors that are similar to those that were commonly used in high-end desktop computers less than fifteen years ago.

Ultimately, computing power and storage capacity will become extremely cheap. Inexpensive devices, home appliances, and consumer products such as microwave ovens, shopping carts, wallets, and toys will include powerful processors and megabytes of storage memory.

Thanks to Moore's Law, software developers for desktop computers and servers haven't had to worry very much about processing power or efficiency of their software. Many performance problems have been resolved simply by waiting for a more powerful computer to become available.

However, the consumer device space and embedded software development are different. Even though the processing power of consumer devices and embedded systems is increasing, the majority of these systems are still very resource-constrained and limited in processing power. And, unlike in the desktop and enterprise computing area, the situation is not likely to change dramatically in the next few years. There are several reasons for this:

  • Moore's Law does not apply to the battery. Most consumer devices are battery-operated. Even though battery technology has advanced substantially in the past years, the advances in battery technology are not as dramatic and predictable as in microprocessor development. Low power consumption is very important in wireless devices, because 75 to 85 percent of the battery power typically needs to be reserved for the radio transmitter and RF signal processing. This places severe power constraints on the rest of the system.

  • High-volume production. Typically, consumer devices such as cellular phones are manufactured in extremely large quantities (millions or even tens of millions of units). They are sold to price-conscious consumers at prices that are very low, often subsidized. To improve their profit margins, device manufacturers want to keep the per-unit costs of the devices as low as possible. Additional processing power or precious dynamic memory will not be added unless the consumers are willing to pay for the extra capabilities.

  • Specialized nature of devices. Consumer devices are typically highly specialized. Each device is usually highly customized for its intended usage: cell phones for voice communication, pagers for alphanumeric message retrieval, digital cameras for photography, and so on. Again, to keep the price of the devices reasonable, device manufacturers are not willing to add general-purpose features and capabilities that would raise the cost of the device, unless the features are well-justified from the viewpoint of the target market and the consumer.

In general, a fundamental difference between desktop/enterprise computing and consumer devices is that in the consumer device space one solution does not fit all. Unlike personal computers, which can run tens of thousands of different kinds of applications, and are not customized particularly well for any single application, consumer devices are typically highly specialized for their intended use and are designed to do only one or a few things well. This means that unlike desktop and enterprise computers, whose performance is typically easy to measure in terms of their processing power, the performance and value of consumer devices and embedded systems is measured in terms of how well they serve their intended usage. The specialized nature of the devices has to be kept in mind when developing software for these devices.

There are further factors differentiating the consumer device space from desktop computers. These include:

  • Small screen size. The majority of consumer devices have miniscule screens compared to desktop computers or servers. Some devices have no screens at all.

  • Different usage models. The usage models of small devices vary considerably. Some are stylus-operated, some have tiny phone keypads operated with one hand only, some have small QWERTY keyboards operated using two thumbs, some are voice-operated/hands-free, and so on.

  • Mobility. Compared to personal computers, consumer devices are operated in varying and sometimes unusual circumstances, for example, while in traffic, while roller skating or skiing, at night, on a beach, in a snowstorm, and so on.

  • Limited network bandwidth with intermittent connections. Personal computer users have become accustomed to relatively reliable, rather high-speed networks based on TCP/IP and other well-established network protocols. In contrast, many wireless devices have intermittent, low-bandwidth network connections.

In summary, the rules that apply to desktop and enterprise software development do not generally apply to consumer devices and embedded software development. Even though from the historical viewpoint it would be quite easy to predict the future of small devices to be similar to the past history of personal computers, it is by no means obvious that the history will actually repeat itself in this context. Rather, at least for the time being, a fundamentally different mindset is required to address the peculiarities of consumer devices, embedded systems, and the consumer market.


3.4 Requirements

This section introduces the technical requirements and constraints that were followed in defining the CLDC and MIDP standards. We start with the hardware and software requirements, and then discuss the specific constraints that Java 2 Micro Edition imposes on its configurations and profiles.

It should be noted that the requirements of CLDC and MIDP are different. CLDC is not targeted to any specific device category, and therefore its requirements are broader than those of MIDP. MIDP is focused specifically on two-way wireless communication devices such as cell phones, and the requirements of MIDP are specific to its target market.

3.4.1 Hardware Requirements of CLDC

CLDC is intended to run on a wide variety of small devices. The underlying hardware capabilities of these devices vary considerably, and therefore the CLDC Specification does not impose any specific hardware requirements other than memory requirements. Even for memory limits, the CLDC Specification defines minimum limits only. The actual CLDC target devices may have significantly more memory than the minimum.

The CLDC Specification assumes that the minimum total memory budget available for the Java Virtual Machine, configuration libraries, profile libraries, and the applications is at least 192 kilobytes. More specifically, it is assumed that:

  • At least 160 kilobytes of non-volatile[3] memory is available for the virtual machine and CLDC libraries.

    [3] The term non-volatile is used to indicate that the memory is expected to retain its contents between the user turning the device "on" or "off." For the purposes of the CLDC Specification and MIDP Specification, it is assumed that non-volatile memory is usually accessed in read mode and that special setup might be required to write to it. Examples of non-volatile memory include ROM, flash, and battery-packed SDRAM. The CLDC Specification or MIDP Specification do not define which memory technology a device must have, nor do they define the behavior of such memory in a power-loss scenario.

  • At least 32 kilobytes of volatile[4] memory is available for the virtual machine runtime (for example, the object heap).

    [4] The term volatile is used to indicate that the memory is not expected to retain its contents between the user turning the device "on" or "off." For the purposes of the CLDC Specification and MIDP Specification, it is assumed that volatile memory can be read from and written to directly. The most common type of volatile memory is DRAM.

The ratio of volatile to non-volatile memory in the total memory budget can vary considerably depending on the target device and the role of the Java platform in the device. If the Java platform is used strictly for running system applications that are built in a device, then applications can be prelinked and preloaded, and a very limited amount of volatile memory is needed. If the Java platform is used for running dynamically downloaded content, then devices will need a higher ratio of volatile memory.

3.4.2 Hardware Requirements of MIDP

The MIDP expert group defined a Mobile Information Device (MID) to be a device that should meet the following minimum requirements:

  • Memory:

    • 256 kilobytes of non-volatile memory for the MIDP components[5]

      [5] Memory requirements cited here are for MIDP components only. MIDP runs on top of CLDC, so the static size of the CLDC implementation must be added to this figure.

    • 8 kilobytes of non-volatile memory for application-created persistent data

    • 128 kilobytes of volatile memory for the virtual machine run time (for example, the object heap)

  • Display:

    • Screen-size: 96x54

    • Display depth: 1-bit

    • Pixel shape (aspect ratio): approximately 1:1

  • Input:

    • One or more of the following user-input mechanisms (see Figure 3.3):

      - "one-handed keypad"

      - "two-handed keyboard"

      - touch screen

  • Networking:

    • Two-way, wireless, possibly intermittent, with limited bandwidth

  • Sound:

    • The ability to play tones, either via dedicated hardware, or via software algorithm.

3.4.3 Software Requirements of CLDC

Like the hardware capabilities, the system software in CLDC target devices varies considerably. For instance, some of the devices might have a full-featured operating system that supports multiple, concurrent operating system processes and a hierarchical file system. Many other devices might have extremely limited system software with no notion of a file system. Faced with such variety, CLDC makes minimal assumptions about the underlying system software.

Generally, the CLDC Specification assumes that a minimal host operating system or kernel is available to manage the underlying hardware. This host operating system must provide at least one schedulable entity to run the Java virtual machine. The host operating system does not need to support separate address spaces or processes, nor does it have to make any guarantees about the real-time scheduling or latency behavior.

3.4.4 Software Requirements of MIDP

For devices meeting the MIDP hardware requirements described in previous subsection, there is a broad range of possible system software capabilities. Unlike the consumer desktop computer model where there are large, dominant system software architectures, the Mobile Information Device (MID) space is characterized by a wide variety of system software. For example, some MIDs might have a full-featured operating system that supports multiprocessing[6] and hierarchical file systems, while other MIDs might have small, thread-based operating systems with no notion of a file system. Faced with such variety, the MIDP Specification, like the CLDC Specification, makes minimal assumptions about system software. These requirements are as follows:

[6] The ability to run multiple, concurrent processes, each with a separate and distinct memory map.

  • A minimal kernel to manage the underlying hardware (that is, handling of interrupts, exceptions, and minimal scheduling). This kernel must provide at least one schedulable entity to run the Java Virtual Machine. The kernel does not need to support separate address spaces (or processes) or make any guarantees about either real-time scheduling or latency behavior.

  • A mechanism to read and write from non-volatile memory to support the MIDP persistence APIs discussed in Chapter 14.

  • Read and write access to the device's wireless networking to support the MIDP networking APIs discussed in Chapter 15.

  • A mechanism to provide a time base for use in time-stamping the records written to persistent storage and to provide the basis of the timer APIs defined in Section 20.1, "Timer Support."

  • A minimal capability to write to a bit-mapped graphics display.

  • A mechanism to capture user input from one (or more) of the three input mechanisms previously discussed.

3.4.5 J2ME Requirements

CLDC is defined as a Java 2 Micro Edition (J2ME™) configuration. MIDP is defined as a Java 2 Micro Edition profile. The rules for J2ME configurations and profiles impose certain additional constraints on the CLDC and MIDP specifications:

  • A J2ME configuration shall only define a minimum complement or the "lowest common denominator" of Java technology. All the features included in a configuration must be generally applicable to a wide variety of devices. Features specific to a certain vertical market, device category, or industry should be defined in a profile. This means that the scope of the Connected, Limited Device Configuration Specification is limited and must generally be complemented by profiles.

  • Since the goal of the J2ME configurations is to guarantee portability and interoperability between various kinds of resource-constrained devices, the configurations do not define any optional features. This limitation has a significant impact on what can be included in the CLDC Specification and what should not be included. More device-specific or optional functionality should generally be avoided, but, if necessary, such functionality must be defined in J2ME optional packages, manufacturer-specific licensee open classes (also known as OEM-specific classes), rather than in the J2ME configuration or profile specifications.

  • A J2ME configuration specification shall generally define a subset of the Java technology features and libraries provided by the Java 2 Platform, Standard Edition (J2SE). Consequently, rather than providing a complete description of all the supported features, the CLDC Specification shall only define the variances and differences compared to the full Java Language Specification (JLS) and Java Virtual Machine Specification (JVMS). If something is not explicitly specified in the CLDC Specification, then it is assumed that a virtual machine conforming to the CLDC Specification shall comply with the JLS and JVMS.

Note that the absence of optional features in CLDC and MIDP does not preclude the use of various implementation-level optimizations. For instance, at the implementation level, alternative bytecode execution techniques (for example, Just-In-Time compilation) or application representation techniques can be used as long as the observable user-level semantics of the implementation remain the same as defined by the CLDC Specification and MIDP Specification.


3.5 Scope of the CLDC and MIDP Standards

3.5.1 Scope of CLDC

Based on the decisions of the JSR 30 and JSR 139 expert groups, the CLDC Specification addresses the following areas:

  • Java language and virtual machine features

  • core libraries (java.lang.*, java.io.*, java.util.*)

  • input/output

  • networking

  • security

  • internationalization

The CLDC Specification intentionally does not address the following functionality areas and features:

  • application life-cycle management (installation, launching, deletion)

  • user interface functionality

  • event handling

  • high-level application model (interaction between the user and the application)

These features can be addressed by profiles implemented on top of the Connected, Limited Device Configuration. In general, the CLDC expert group intentionally kept small the number of areas addressed by the CLDC Specification in order not to exceed the strict memory limitations or to exclude any particular device category.

3.5.2 Scope of MIDP

Mobile Information Devices (MIDs) span a potentially wide set of capabilities. Rather than try to address all such capabilities, the MIDP 1.0 expert group agreed to limit the set of APIs specified, addressing only those APIs that were considered absolute requirements to achieve broad portability.

These APIs are:

  • application model (that is, defining the semantics of a MIDP application and how the application is controlled)

  • user interface (includes display and input)

  • persistent storage

  • networking

  • timers

The MIDP 2.0 expert group expanded upon these APIs to add the highest priority functionality identified as missing after the experience of the initial MIDP device deployments. The added MIDP 2.0 APIs are:

  • sounds

  • 2D games

  • MIDlet signing model for added security

  • end-to-end security through HTTPS and secure sockets

  • application delivery and installation

By the same reasoning, some areas of functionality were considered to be outside the scope of the MIDP expert groups. These areas include:

  • System-level APIs: The emphasis of the Mobile Information Device Profile is on enabling application programming rather than enabling system programming. Thus, low-level APIs that specify a system interface to, for example, power management or voice CODECs, are beyond the scope of the MIDP Specification.

  • Low-level security[7]: MIDP specifies no additional low-level security features other than those provided by the CLDC.

    [7] Low-level security (also known as virtual machine security) ensures that an ill-formed or maliciously encoded class file does not crash the virtual machine or the device.

  • Application-level cryptography[8]: MIDP specifies no explicit cryptography APIs, although MIDlet Suite Security is described in Chapter 18.

    [8] Application-level cryptography defines which APIs and system resources the application can access.

At first glance, the scope of the MIDP Specification might seem limited. However, given the broad range of devices that the MIDP Specification addresses, the MIDP expert group felt that it would be better to concentrate on a small set of common, required functionality, and by doing so create a "lowest common denominator" platform where none exists today. In particular, the MIDP expert group did not want to mandate features that cannot be supported easily on all the MIDP target devices and wireless networks.


Chapter 4. Connected Limited Device Configuration

This chapter introduces the Connected, Limited Device Configuration (CLDC), one of the core building blocks of the Java™ 2 Platform, Micro Edition (J2ME™). The goal of the Connected, Limited Device Configuration is to provide a standardized, highly portable, minimum-footprint Java application development platform for resource-constrained, connected devices. The CLDC target devices are characterized generally as follows:

  • at least 192 kilobytes of total memory budget available for the Java platform,

  • a 16-bit or 32-bit processor,

  • low power consumption, often operating with battery power, and

  • connectivity to some kind of network, often with a wireless, intermittent connection and with limited (often 9600 bps or less) bandwidth.

CLDC is core technology that can be used as the basis for one or more J2ME profiles. Cell phones, two-way pagers, personal digital assistants (PDAs), organizers, home appliances, low-end TV set-top boxes, and point-of-sale terminals are some, but not all, of the devices that might be supported by the Connected, Limited Device Configuration.

The material in this chapter comes from the CLDC Specification document that is available from the Java Community Process (JCP) web site.[1] The CLDC Specification defines the minimum required complement of Java technology components and libraries for small connected devices. Java language and virtual machine features, core libraries, input/output, networking, and security are the primary topics addressed by the CLDC Specification.


4.1 CLDC Expert Groups

4.1.1 CLDC 1.0 Expert Group

The CLDC Specification version 1.0, completed in May 2000, was the result of the work of a Java Community Process (JCP) expert group JSR 30 consisting of a large number of industrial partners. The following 18 companies (in alphabetical order) were members of the CLDC 1.0 expert group:

• America Online | • Oracle
• Bull | • Palm Computing
• Ericsson | • Research In Motion (RIM)
• Fujitsu | • Samsung
• Matsushita | • Sharp
• Mitsubishi | • Siemens
• Motorola | • Sony
• Nokia | • Sun Microsystems
• NTT DoCoMo | • Symbian

4.1.2 CLDC 1.1 Expert Group

The CLDC Specification version 1.1 was produced by the Java Community Process (JCP) expert group JSR 139 consisting of the following full members:

• aJile Systems | • Openwave Systems
• Aplix Corporation | • Oracle
• France Telecom | • Panasonic
• Fujitsu | • Research In Motion
• Insignia Solutions | • Samsung
• Liberate Technologies | • Siemens
• Mitsubishi Electric | • Sony
• Motorola | • Sony Ericsson Mobile Communications
• NEC | • Sun Microsystems
• Nokia | • Symbian
• NTT DoCoMo | • Vulcan Machines
• OpenTV | • Zucotto Wireless


4.2 CLDC Architecture, Application Model, and Security

4.2.1 Architectural Overview

The high-level architecture of a typical CLDC device is illustrated in Figure 4.1. At the heart of a CLDC implementation is the Java Virtual Machine, which, apart from specific differences defined later in this chapter, is compliant with the Java™ Virtual Machine Specification and Java™ Language Specification. The virtual machine typically runs on top of a host operating system that provides the necessary capabilities to manage the underlying hardware. As explained in Section 3.4.3, "Software Requirements of CLDC," the CLDC Specification makes minimal assumptions about the capabilities of the host operating system.

Figure 4.1. Architecture overview of a CLDC target device

On top of the virtual machine are the Java libraries. These libraries are divided broadly into two categories:

  1. those defined by the Connected, Limited Device Configuration (CLDC Libraries), and

  2. those defined by profiles (such as MIDP) and optional packages.

Libraries defined by the Connected, Limited Device Configuration are discussed in Chapter 5. Libraries defined by profiles are outside the scope of the CLDC Specification. The libraries supported by the Mobile Information Device Profile are discussed in Chapters 8 through 20.

4.2.2 The Concept of a Java Application

Connected, Limited Device Configuration is not targeted to any specific device category. Many of the target devices may have an advanced graphical user interface, some target devices may be operated from a textual, character-based user interface, while some other target devices may not have any visual user interface or display at all. To cater to such a broad variety of devices, the application model defined in the CLDC Specification is intentionally very simple.

In the CLDC Specification, the term Java application is used to refer to a collection of Java class files containing a single, unique method main that identifies the launch point of the application. As specified in the Java™ Virtual Machine Specification (JVMS) Sections 5.2 and 2.17.1, the method main must be declared public, static, and void, as shown below:

public static void main(String[] args)

A virtual machine conforming to CLDC starts the execution of a Java application by calling the method main.

J2ME profiles such as MIDP define alternative application models that extend or override the basic application model defined by the CLDC Specification.

4.2.3 Application Security

The total amount of code devoted to security in the Java 2 Platform, Standard Edition far exceeds the total memory budget available for CLDC. Therefore, some simplifications are necessary when defining the security model for CLDC applications. Basically, the security model of CLDC can be examined at three different levels:

  • Low-level security (also known as virtual machine security). Ensures that the applications running in the virtual machine follow the semantics of the Java programming language, and that an ill-formed or maliciously encoded class file does not crash or in any other way harm the target device.

  • Application-level security. Means that a Java application running on a device can access only those libraries, system resources, and other components that the device and the Java application environment allows it to access.

  • End-to-end security. Refers to a model that guarantees that any transaction initiated on a device is protected along the entire path from the device to/from the entity providing the services for that transaction (e.g, a server located on the Internet). Encryption or other means may be necessary to achieve this. End-to-end security is outside the scope of the CLDC Specification.

Below we take a more detailed look at low-level security and application-level security requirements.

Low-level security

A key requirement for a Java virtual machine in a mobile information device is low-level security. An application running in the virtual machine must not be able to harm the device in which the virtual machine is running, or crash the device. In a standard Java virtual machine implementation, this constraint is guaranteed by the class file verifier, which ensures that the bytecodes and other items stored in class files cannot contain illegal instructions, cannot be executed in an illegal order, and cannot contain references to invalid memory locations or memory areas that are outside the Java object memory (the object heap). In general, the role of the class file verifier is to ensure that class files loaded into the virtual machine do not execute in any way that is not allowed by the Java™ Virtual Machine Specification.

As will be explained in more detail later, the CLDC Specification requires that a Java virtual machine conforming to the CLDC standard must be able to reject invalid class files. This is guaranteed by the class file verification technology presented in Section 4.4.2, "Class File Verification."

Application-level security

Even though class file verification plays a critical role in ensuring the security of the Java platform, the security provided by the class file verifier is insufficient by itself. The class file verifier can only guarantee that the given program is a valid Java application and nothing more. There are still several other potential security threats that will go unnoticed by the verifier. For instance, access to external resources such as the file system, printers, infrared devices, native libraries, or the network is beyond the scope of the class file verifier. By application-level security, we mean that a Java application can access only those libraries, system resources, and other components that the device and the Java application environment allows it to access.

In CLDC, application-level security is accomplished by using a metaphor of a closed "sandbox." A CLDC application runs in a closed environment in which the application can access only those libraries that have been defined by the configuration, profiles, optional packages, and other classes supported by the device. Java applications cannot escape from this sandbox or access any libraries or resources that are not part of the predefined functionality. The sandbox ensures that a malicious or possibly erroneous application cannot gain access to system resources.

More specifically, the CLDC sandbox model requires that:

  • Class files must be properly verified and guaranteed to be valid Java applications. (Class file verification is discussed in more detail in Section 4.4.2, "Class File Verification.")

  • The downloading, installation, and management of Java applications on the device takes place in such a way that the application programmer cannot modify or bypass the standard class loading mechanisms of the virtual machine.

  • A closed, predefined set of Java APIs is available to the application programmer, as defined by CLDC, profiles, optional packages, and manufacturer-specific classes.

  • The set of native functions accessible to the virtual machine is closed, meaning that the application programmer cannot download any new libraries containing native functionality or access any native functions that are not part of the Java libraries provided by CLDC, profiles, optional packages, or manufacturer-specific classes.

For security reasons, the CLDC Specification also defines some additional requirements related to the interplay between system classes and application classes. For instance, a CLDC implementation is required to ensure that the application programmer cannot override, modify, or add any classes to system packages such as java.*, javax.microedition.*, or profile-specific packages, or manipulate the built-in class file lookup order in any way. Class file lookup order is discussed in more detail in Section 4.4.3, "Class File Format and Class Loading."

In addition, it is required that a CLDC application can load application classes only from its own Java Archive (JAR) file. This restriction ensures that Java applications on a device cannot interfere with each other or steal data from each other. Additionally, this ensures that a third-party application cannot gain access to the private or protected components of the Java classes that the device manufacturer or a service provider may have provided as part of the system applications. JAR files and applications representation formats are discussed in more detail in Section 4.4.3, "Class File Format and Class Loading."

J2ME profiles such as MIDP may define additional security solutions on top of those provided by CLDC. MIDP security will be discussed in detail in Chapter 16, "Secure Networking" and Chapter 18, "Security for MIDlet Suites."

4.2.4 Application Management

Many small, resource-constrained devices do not have a file system or any other conventional mechanism for storing dynamically downloaded information on the device. Therefore, a CLDC implementation does not require that Java applications downloaded from an external source are stored persistently on the device. Rather, the implementation might just load the application and discard it immediately after execution.

However, in many potential CLDC devices, it is beneficial to be able to execute the same Java applications multiple times without having to download the applications over and over again. This is particularly important if applications are being downloaded over a wireless network, and the user could incur high downloading expenses. If a device implementing CLDC is capable of storing applications persistently, we assume that the device implementing has capabilities for managing the applications that have been stored in the device. At the high level, application management refers to the ability to

  • download and install Java applications,

  • inspect existing Java applications stored on the device,

  • select and launch Java applications, and

  • delete existing Java applications.

Depending on the resources available on the device, a CLDC system may allow multiple Java applications to execute concurrently or can restrict the system to permit the execution of only one Java application at a time. It is up to the particular implementation to decide whether the execution of multiple Java applications is supported by utilizing the multiprocessing capabilities (if they exist) of the underlying host operating system or by instantiating multiple logical virtual machines to run the concurrent Java applications.

Due to significant variations and feature differences among potential CLDC devices, the details of application management are highly device-specific and implementation-dependent. The actual details of application management are outside the scope of the CLDC Specification. Application management issues in the context of the Mobile Information Device Profile are discussed in Section 19.2, "MIDP System Software."


4.3 Java Language Specification Compatibility

The general goal for a virtual machine conforming to CLDC is to be as compliant with the Java™ Language Specification as is feasible within the strict memory limits of CLDC target devices. This section summarizes the differences between a virtual machine conforming to CLDC and the Java Virtual Machine of Java 2 Standard Edition (J2SE). Except for the differences indicated herein, a virtual machine conforming to CLDC is compatible with The Java™ Language Specification, Second Edition, by James Gosling, Bill Joy, Guy L. Steele, and Gilad Bracha, Addison-Wesley, 2000, ISBN 0-201-31008-2.

Note

For the remainder of this book, the Java™ Language Specification is referred to as JLS. Sections within the Java™Language Specification are referred to using the § symbol. For example, (JLS §4.2.4).

4.3.1 No Finalization of Class Instances

CLDC libraries do not include the method java.lang.Object.finalize(). Therefore, a virtual machine conforming to CLDC does not support finalization of class instances (JLS §12.6). No application built to conform to the Connected, Limited Device Configuration can require that finalization be available.

4.3.2 Error-Handling Limitations

A virtual machine conforming to CLDC generally supports exception handling as defined in JLS Chapter 11, with the exception that asynchronous exceptions (JLS §11.3.2) are not supported.

In contrast, the set of error classes included in CLDC libraries is limited, and consequently the error-handling capabilities of CLDC are considerably more limited. This is because of two reasons:

  1. In embedded systems, recovery from error conditions is usually highly device-specific. Application programmers cannot be expected to know about device-specific error-handling mechanisms and conventions.

  2. As specified in JLS §11.5, class java.lang.Error and its subclasses are exceptions from which programs are not ordinarily expected to recover. Implementing the error-handling capabilities fully according to the Java™ Language Specification is rather expensive, and mandating the presence and handling of all the error classes would impose an overhead on the virtual machine implementation.

A virtual machine conforming to CLDC provides a limited set of error classes defined in Section 5.2.7, "Exception and Error Classes." When encountering any other error, the implementation behaves as follows:

  • either the virtual machine halts in an implementation-specific manner,

  • or the virtual machine throws an Error that is the nearest CLDC-supported superclass of the Error class that must be thrown according to the Java™ Language Specification.

If the virtual machine conforming to CLDC implements additional error checks that are part of the Java™ Language Specification but that are not required by the CLDC Specification, the implementation shall throw the nearest CLDC-supported superclass of the Error class that is defined by the Java™ Language Specification.


4.4 Java Virtual Machine Specification Compatibility

The general goal for a virtual machine conforming to CLDC is to be as compliant with the Java™ Virtual Machine Specification as is possible within strict memory constraints of CLDC target devices. This section summarizes the differences between a virtual machine conforming to CLDC and the Java Virtual Machine of Java 2 Standard Edition (J2SE). Except for the differences indicated herein, a virtual machine conforming to CLDC is compatible with the Java Virtual Machine as specified in the The Java™ Virtual Machine Specification, Second Edition by Tim Lindholm and Frank Yellin. Addison-Wesley, 1999, ISBN 0-201-43294-3.

Note

For the remainder of this book, the Java™ Virtual Machine Specification is referred to as JVMS. Sections within the Java™ Virtual Machine Specification are referred to using the § symbol. For example, (JVMS §2.4.3).

4.4.1 Features Eliminated from the Virtual Machine

A number of features have been eliminated from a virtual machine conforming to CLDC because the Java libraries included in CLDC are substantially more limited than libraries in Java 2 Standard Edition, and/or the presence of those features would have posed security problems in the absence of the full J2SE security model. The eliminated features include:

  • user-defined class loaders (JVMS §5.3.2),

  • thread groups and daemon threads (JVMS §2.19, §8.12),

  • finalization of class instances (JVMS §2.17.7), and

  • asynchronous exceptions (JVMS §2.16.1).

In addition, a virtual machine conforming to CLDC has a significantly more limited set of error classes than a full J2SE virtual machine.

Applications written to conform to the Connected, Limited Device Configuration shall not rely on any of the features above. Each of the features in this list is discussed in more detail next.

User-defined class loaders

A virtual machine conforming to CLDC does not support user-defined, Java-level class loaders (JVMS §5.3, §2.17.2). A virtual machine conforming to CLDC has a built-in "bootstrap" class loader that cannot be overridden, replaced, or reconfigured. The elimination of user-defined class loaders is part of the security restrictions of the CLDC Specification.

Thread groups and daemon threads

A virtual machine conforming to CLDC implements multithreading, but does not have support for thread groups or daemon threads (JVMS §2.19, §8.12). Thread operations such as starting of threads can be applied only to individual thread objects. If application programmers want to perform thread operations for groups of threads, explicit collection objects (such as instances of classes Hashtable or Vector) must be used at the application level to store the thread objects.

Finalization of class instances

CLDC libraries do not include the method java.lang.Object.finalize(). Therefore, a virtual machine conforming to CLDC does not support finalization of class instances (JVMS §2.17.7). No application built to conform to the Connected, Limited Device Configuration can require that finalization be available.

Errors and asynchronous exceptions

As discussed earlier in Section 4.3.2, "Error-Handling Limitations," the error-handling capabilities of a virtual machine conforming to CLDC are limited.

A virtual machine conforming to CLDC supports the set of Error classes defined in Section 5.2, "Classes Derived from Java 2 Standard Edition." When encountering any other error, the implementation shall behave as follows:

  • either the virtual machine halts in an implementation-specific manner,

  • or the virtual machine throws an Error that is the nearest CLDC-supported superclass of the Error class that must be thrown according to the Java™ Virtual Machine Specification.

If the virtual machine conforming to CLDC implements additional error checks that are part of the Java™ Virtual Machine Specification but that are not required by the CLDC Specification, the implementation will throw the nearest CLDC-supported superclass of the Error class that is defined by the Java™ Virtual Machine Specification.

A virtual machine conforming to CLDC generally supports exception handling as defined by Java™ Virtual Machine Specification. However, a virtual machine conforming to CLDC does not support asynchronous exceptions (JVMS §2.16.1).

4.4.2 Class File Verification

Like the Java Virtual Machine of Java 2 Standard Edition, a virtual machine conforming to CLDC must be able to reject invalid class files. However, since the static and dynamic memory footprint of the standard class file verifier is excessive for a typical CLDC target device, an alternative solution is defined in the CLDC Specification. This solution is described below.

Off-device preverification and runtime verification with stack maps

The existing J2SE class file verifier defined in the Java™ Virtual Machine Specification (JVMS §4.9) is not ideal for small, resource-constrained devices. The J2SE verifier takes a minimum of 50 kilobytes of binary code space and typically at least 30 to 100 kilobytes of dynamic RAM at run time. In addition, the CPU power needed to perform the complex dataflow algorithm in the conventional verifier can be substantial.

The verification approach described in this subsection is significantly smaller and more efficient in resource-constrained devices than the existing J2SE verifier. The implementation of the new verifier in Sun's CLDC reference implementation requires about 12 kilobytes of Intel x86 binary code and less than 100 bytes of dynamic RAM at run time for typical class files. The verifier performs only a linear scan of the bytecode, without the need of a costly dataflow algorithm.

The CLDC class file verifier operates in two phases, as depicted in Figure 4.2.

  • First, class files have to be run through a special preverifier tool in order to remove certain bytecodes and augment the class files with additional StackMap attributes to speed up runtime verification. The preverification phase is typically performed on the development workstation that the application developer uses for writing and compiling the applications.

  • At run time, the runtime verifier component of the virtual machine uses the additional StackMap attributes generated by the preverifier to perform the actual class file verification efficiently. The execution of bytecodes in a class file can start only when the class file has successfully passed the runtime verifier.

Figure 4.2. Two-phase class file verification in CLDC

Runtime class file verification guarantees type safety. Classes that pass the runtime verifier cannot, for example, violate the type system of the Java virtual machine or corrupt the memory. Unlike approaches based on code signing, such a guarantee does not rely on the predefined verification information to be authentic or trusted. A missing, incorrect, or corrupted StackMap attribute causes the class to be rejected by the runtime verifier.

The new verifier requires the methods in class files to contain a special StackMap attribute. The preverifier tool inserts this attribute into normal class files. A transformed class file is still a valid Java class file, with additional StackMap attributes (refer to the CLDC Specification for further details) that allow verification to be carried out efficiently at run time. These attributes are automatically ignored by the conventional class file verifier used in Java 2 Standard Edition, so the solution is fully upward compatible with the Java Virtual Machine of Java 2 Standard Edition. Preprocessed class files containing the extra attributes are approximately 5 to 15 percent larger than the original, unmodified class files.

Additionally, the new verifier requires that all the subroutines in the bytecodes of class files are inlined. In Java class files, subroutines are special bytecode sequences that contain the bytecodes jsr, jsr_w, ret, or wide ret. The inlining process removes all the jsr, jsr_w, ret, and wide ret bytecodes from all the methods in class files, replacing these instructions with semantically equivalent bytecode. The inlining process makes runtime verification significantly easier and faster.

The new verification process and the format of the StackMap attribute have been specified in more detail in the CLDC Specification.

4.4.3 Class File Format and Class Loading

An essential requirement for the Connected, Limited Device Configuration is the ability to support dynamic downloading of Java applications and third-party content. The dynamic class loading mechanism of the Java platform plays a central role in this. This section discusses the application representation formats and class loading practices required of a virtual machine conforming to CLDC.

Supported file formats

A CLDC implementation must be able to read standard class files (defined in JVMS Chapter 4) with the preverification changes discussed above. In addition, a CLDC implementation must support compressed Java Archive (JAR) files. Detailed information about the JAR format is provided at http://java.sun.com/products/jdk/1.2/docs/guide/jar/. Network bandwidth conservation is very important in low-bandwidth wireless networks. The compressed JAR format provides 30 to 50 percent compression over regular class files without loss of any symbolic information or compatibility problems with existing Java systems.

A CLDC implementation must be able to read Java class files in all the formats supported by Java 2 Platform Standard Edition, JDK versions 1.1, 1.2, 1.3, and 1.4.

Note

The class file formats used by different JDK versions are as follows[2] :

[2] In practice, the situation is a bit more complicated. In pre-JDK 1.4 releases, the javac compiler produced class files in 45.3 format for compatibility with the older versions of the JDK. In JDK 1.4, javac produces 46.0 (JDK 1.2) files by default. However, the compiler can be instructed to produce other class file formats using the "-target" option. For instance, "javac -target 1.1" would produce 45.3 class files.

- The 45.* (usually 45.3) version number identifies JDK 1.1 class files.

- The 46.* version number identifies JDK 1.2 class files.

- The 47.* version number identifies JDK 1.3 class files.

- The 48.* version number identifies JDK 1.4 class files.

A virtual machine conforming to CLDC should be able to read Java class files in any of the formats listed above. However, the virtual machine is allowed to ignore certain class file attributes that the CLDC implementation does not need. More specifically, the following attributes can be ignored by a CLDC implementation:

  • The Synthetic attribute (JVMS §4.7.6)

  • The SourceFile attribute (JVMS §4.7.7)

  • The LineNumberTable attribute (JVMS §4.7.8)

  • The LocalVariableTable attribute (JVMS §4.7.9)

  • The Deprecated attribute (JVMS §4.7.10)

Public representation of Java applications and resources

A Java application is considered to be "represented publicly" or "distributed publicly" when the system it is stored on is open to the public and the transport layers and protocols it can be accessed with are open standards. In contrast, a device can be part of a closed network environment where the vendor (such as the operator of a wireless network) controls all communication. In this case, the application is no longer represented publicly once it enters and is distributed via the closed network system.

Whenever Java applications intended for a CLDC device are represented publicly, the compressed JAR file representation format must be used. The JAR file must contain regular class files with the following restrictions and additional requirements:

  1. StackMap attributes (see CLDC Specification version 1.1, Appendix 1, for details) must be included in class files.

  2. The class files must not contain any of the following bytecodes: jsr (JVMS p. 304, jsr_w (JVMS p. 305), ret (JVMS p. 352), and wide ret (JVMS p. 360).

Sun's CLDC reference implementation includes a preverification tool for performing these modifications to a class file. The stack map attributes are automatically ignored by the conventional class file verifier described in JVMS §4.9. That is, the modified class file format is fully upward compatible with other Java environments such as J2SE or J2EE.

Additionally, the JAR file may contain application-specific resource files that can be loaded into the virtual machine by calling method Class.getResourceAsStream(String name).

Class file lookup order

The Java™ Language Specification and Java™ Virtual Machine Specification do not specify the order in which class files are searched when new class files are loaded into the virtual machine. At the implementation level, a typical virtual machine implementation uses the environment variable CLASSPATH to define the lookup order.

The CLDC Specification assumes class file lookup order to be implementation-dependent, with the restrictions described in the next paragraph. The lookup strategy is typically defined as part of the application management implementation (see Section 4.2.4, "Application Management.") A virtual machine conforming to CLDC is not required to support the notion of CLASSPATH, but may do so at the implementation level.

Two restrictions apply to class file lookup order. First, a virtual machine conforming to CLDC must guarantee that the application programmer cannot override, modify, or add new system classes (classes belonging to CLDC, profiles, or other libraries) in any way. Second, it is required that the application programmer must not be able to manipulate the class file lookup order in any way. Both of these restrictions are important for security reasons.

Implementation optimizations

The CLDC Specification mandates the use of compressed JAR files for Java applications that are represented and distributed publicly. However, in closed network environments (see the discussion above) and internally inside the virtual machine at run time, alternative application representation formats can be used. For instance, in low-bandwidth wireless networks it is often advised to use alternative, more compact transport formats at the network transport level to conserve network bandwidth. Similarly, when storing the downloaded applications in devices, more compact representations can be used as long as the observable user-level semantics of the applications remain the same as with the public representation required by the CLDC Specification. The definition of more compact class file representations is assumed to be implementation-dependent and outside the scope of the CLDC Specification.

Preloading/prelinking ("ROMizing")

A virtual machine conforming to CLDC may choose to preload and prelink some classes to reduce class loading time at run time. This technology is often referred to informally as ROMizing.[3]

[3] The term ROMizing is somewhat misleading, since this technology can be used independent of any specific memory technology. ROMized class files do not necessarily have to be stored in ROM.

Typically, small virtual machine implementations choose to preload all the system classes (for instance, classes belonging to a specific configuration or profile) and perform application loading dynamically.

The actual mechanisms for preloading are implementation-dependent and beyond the scope of the CLDC Specification. In all cases, the runtime effect and semantics of preloading/prelinking must be the same as if the actual class had been loaded in at that point. There must be no visible effects from preloading other than the possible speed-up in application launching. In particular, any class initialization that has a user-visible effect must be performed at the time the class would first have been used if it had not been preloaded into the system.

Application representation format optimizations

Java class files are not optimized for network transport in limited bandwidth environments. Each Java class file is an independent unit that contains its own constant pool (symbol table), method, field and exception tables, bytecodes, exception handlers, and some other information. The self-contained nature of class files is one of the virtues of Java technology, allowing applications to be composed of multiple pieces that do not necessarily have to reside in the same location, making it possible to extend applications dynamically at run time. However, this flexibility has its price. If Java applications were treated as a sealed unit, a lot of space could be saved by removing the redundancies in multiple constant pools and other structures, especially if full symbolic information was left out. Also, one of the desirable features of an application transport format in a limited-power computing environment is the ability to execute applications "in place," without any special loading or conversion process between the static representation and runtime representation. The CLDC Specification allows the use of such formats at the implementation level as long as the public application representation and the publicly observable semantics of the CLDC implementation remain the same as with the original representation required by the CLDC Specification.

The definition of alternative application representation formats is implementation-dependent and outside the scope of the CLDC Specification.


4.5 New for CLDC 1.1

The CLDC 1.1 (JSR 139) expert group members were generally satisfied with the CLDC Specification version 1.0 and did not see any need for radical changes in the new specification. Therefore, CLDC Specification version 1.1 is primarily an incremental release that is intended to be fully backwards compatible with CLDC Specification version 1.0. Some important new functionality, such as floating point support, has been added.

The list below summarizes the main differences between CLDC Specification versions 1.1 (JSR 139) and 1.0 (JSR 30). Those differences that are specific to Java libraries supported by CLDC are summarized in Section 5.4, "New for CLDC 1.1."

  • Floating point support has been added.

    • All floating point bytecodes are supported by CLDC 1.1.

    • Classes Float and Double have been added, and various methods have been added to the other library classes to handle floating point values. (Refer to Section 5.4, "New for CLDC 1.1," and the CLDC Almanacs at the end of this book for a detailed summary of the changes.)

  • Weak reference support (small subset of the J2SE weak reference classes) has been added.

  • Error-handling requirements have been clarified, and one new error class, NoClassDefFoundError, has been added.

  • In CLDC 1.1, Thread objects have names like threads in J2SE do. The method Thread.getName() has been introduced, and the Thread class has a few new constructors that have been inherited from J2SE.

  • In CLDC 1.1, Threads can be interrupted using the Thread.interrupt method.

  • Minimum total memory budget for CLDC has been increased from 160 to 192 kilobytes, mainly because of the added floating point functionality.

  • Much more detailed verifier specification ("CLDC Byte Code Typechecker Specification") is provided as an appendix of the CLDC Specification version 1.1.


Chapter 5. CLDC Libraries

Java 2 Platform, Standard Edition (J2SE) and Java 2 Platform, Enterprise Edition (J2EE) provide a very rich set of Java class libraries for the development of enterprise applications for desktop computers and servers. Unfortunately, these libraries require tens of megabytes of memory to run and are therefore unsuitable for small devices with limited resources. In this chapter we introduce the class libraries supported by the Connected, Limited Device Configuration.


5.1 Background and Goals

A general goal for designing the libraries for the Connected, Limited Device Configuration was to provide a minimum useful set of libraries for practical application development and profile definition for a variety of small devices. As explained earlier in Section 3.1, "High-Level Goals," CLDC is a "lowest common denominator" standard that includes only minimal Java platform features and APIs for a wide range of consumer devices. Given the strict memory constraints and differing features of today's small devices, it is virtually impossible to come up with a set of libraries that would be ideal for all devices. No matter where the bar for feature inclusion is set, the bar is inevitably going to be too low for some devices and users, and too high for many others.

To ensure upward compatibility with the larger editions of the Java 2 Platform, the majority of the libraries included in CLDC are a subset of Java 2 Standard Edition (J2SE) and Java 2 Enterprise Edition (J2EE). While upward compatibility is a very desirable goal, J2SE and J2EE libraries have strong internal dependencies that make subsetting them difficult in important areas such as security, input/output, user interface definition, networking, and storage. These dependencies are a natural consequence of design evolution and reuse that has taken place during the development of the libraries over time. Unfortunately, these dependencies make it difficult to take just one part of the libraries without including several others. For this reason, some of them have been redesigned, especially in the area of networking.

The libraries defined by the CLDC Specification can be divided broadly into two categories:

  1. those classes that are a subset of standard J2SE libraries, and

  2. those classes that are specific to CLDC (but that can be mapped onto J2SE).

Classes belonging to the former category are located in packages java.lang, java.util, and java.io. These classes have been derived from Java 2 Standard Edition version 1.3.1. A list of these classes is presented in Section 5.2, "Classes Derived from Java 2 Standard Edition."

Classes belonging to the latter category are located in package javax.microedition. These classes are discussed in Section 5.3, "CLDC-Specific Classes."


5.2 Classes Derived from Java 2 Standard Edition

CLDC provides a number of classes that have been derived from Java 2 Standard Edition (J2SE). The rules for J2ME configurations require that each class with the same name and package name as a J2SE class must be identical to or a subset of the corresponding J2SE class. The semantics of the classes and their methods included in the subset may not be changed. The classes may not add any public or protected methods or fields that are not available in the corresponding J2SE classes.

5.2.1 System Classes

J2SE class libraries include several classes that are intimately coupled with the Java Virtual Machine. Similarly, several commonly used Java tools assume the presence of certain classes in the system. For instance, the standard Java compiler (javac) generates code that requires certain methods of classes String and StringBuffer to be available.

The system classes included in the CLDC Specification are listed below. Each of these classes is a subset of the corresponding class in J2SE. Note that in CLDC 1.1, many of these classes contain additional methods that are not present in CLDC 1.0. Refer to CLDC library documentation in the end of this book for more details on each class, as well as for the differences between CLDC 1.0 and 1.1.

java.lang.Object
java.lang.Class
java.lang.Runtime
java.lang.System
java.lang.Thread
java.lang.Runnable (interface)
java.lang.String
java.lang.StringBuffer
java.lang.Throwable

5.2.2 Data Type Classes

The following basic data type classes from package java.lang are supported. Each of these classes is a subset of the corresponding class in J2SE. Classes Float and Double are new in CLDC 1.1.

java.lang.Boolean
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.Character

5.2.3 Collection Classes

The following collection classes from package java.util are supported.

java.util.Vector
java.util.Stack
java.util.Hashtable
java.util.Enumeration (interface)

5.2.4 Input/Output Classes

The following classes from package java.io are supported.

java.io.InputStream
java.io.OutputStream
java.io.ByteArrayInputStream
java.io.ByteArrayOutputStream
java.io.DataInput (interface)
java.io.DataOutput (interface)
java.io.DataInputStream
java.io.DataOutputStream
java.io.Reader
java.io.Writer
java.io.InputStreamReader
java.io.OutputStreamWriter
java.io.PrintStream

5.2.5 Calendar and Time Classes

CLDC includes a small subset of the standard J2SE classes java.util.Calendar, java.util.Date, and java.util.TimeZone. To conserve space, the CLDC Specification requires only one time zone to be supported. By default, this time zone is GMT. Additional time zones may be provided by manufacturer-specific implementations of CLDC as long as the time zones are compatible with those provided by Java 2 Standard Edition.

java.util.Calendar
java.util.Date
java.util.TimeZone

5.2.6 Additional Classes

Two additional utility classes are provided. Class java.util.Random provides a simple pseudo-random number generator that is useful for implementing applications such as games. Class java.lang.Math provides methods min, max, and abs, which are frequently used by other Java library classes. In CLDC 1.1, class java.lang.Math also includes support for floating point trigonometric functions and square root calculation, as well as some additional utility functions such as ceil and floor.

java.util.Random
java.lang.Math

5.2.7 Exception and Error Classes

Since the libraries included in CLDC are generally intended to be compatible with J2SE libraries, the library classes included in CLDC throw precisely the same exceptions as regular J2SE classes do. Consequently, a fairly comprehensive set of exception classes has been included.

In contrast, as explained in Section 4.3.2, "Error-Handling Limitations," the error-handling capabilities of CLDC are limited. By default, a virtual machine conforming to CLDC is required to provide only the error classes listed below. (Class NoClassDefFoundError was added to the libraries in CLDC 1.1.)

Error classes
java.lang.Error
java.lang.NoClassDefFoundError
java.lang.OutOfMemoryError
java.lang.VirtualMachineError
Exception classes
java.lang.Exception
java.lang.ArithmeticException
java.lang.ArrayIndexOutOfBoundsException
java.lang.ArrayStoreException
java.lang.ClassCastException
java.lang.ClassNotFoundException
java.lang.IllegalAccessException
java.lang.IllegalArgumentException
java.lang.IllegalMonitorStateException
java.lang.IllegalThreadStateException
java.lang.IndexOutOfBoundsException
java.lang.InstantiationException
java.lang.InterruptedException
java.lang.NegativeArraySizeException
java.lang.NullPointerException
java.lang.RuntimeException
java.lang.NumberFormatException
java.lang.SecurityException
java.lang.StringIndexOutOfBoundsException

java.util.EmptyStackException
java.util.NoSuchElementException

java.io.EOFException
java.io.InterruptedIOException
java.io.IOException
java.io.UnsupportedEncodingException
java.io.UTFDataFormatException

5.2.8 Weak References

As of CLDC Specification version 1.1, the following classes are supported:

java.lang.ref.Reference
java.lang.ref.WeakReference

5.2.9 Internationalization Support

Character sets and character case conversion support

A CLDC implementation is required to support Unicode characters. Character information is based on the Unicode Standard, version 3.0. However, since the full character case conversion tables required for Unicode support are excessively large for devices with tight memory budgets, by default the case conversion facilities in CLDC assume the presence of ISO Latin-1 range of characters only. More specifically, implementations must provide support for character properties and case conversions for characters in the "Basic Latin" and "Latin-1 Supplement" blocks of Unicode 3.0. Other Unicode character blocks may be supported as necessary.

Character encodings

CLDC includes limited support for the translation of Unicode characters to and from a sequence of bytes. In J2SE this is done using objects called Readers and Writers, and this same mechanism is utilized in CLDC using the InputStreamReader and OutputStreamWriter classes with identical constructors.

new InputStreamReader(InputStream is);
new InputStreamReader(InputStream is, String enc)
    throws UnsupportedEncodingException;
new OutputStreamWriter(OutputStream os);
new OutputStreamWriter(OutputStream os, String enc)
    throws UnsupportedEncodingException;

If the enc parameter is present, it is the name of the encoding to be used. Where it is not, a default encoding (defined by the system property microedition.encoding) is used. Additional converters may be provided by manufacturer-specific implementations of CLDC. If a converter for a certain encoding is not available, an UnsupportedEncodingException is thrown.

For official information on character encodings in J2SE, refer to: http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html.

No localization support

Note that CLDC does not provide any localization features. All the solutions related to the formatting of dates, times, currencies and so on are assumed to be outside the scope of the CLDC Specification.

5.2.10 Property Support

CLDC libraries do not include the java.util.Properties class familiar from Java 2 Standard Edition. In J2SE, that class is used for storing system properties such as the name of the host operating system, version number of the virtual machine and so on.

In CLDC, a limited set of system properties described in Table 5.1 is available. These properties can be accessed by calling the method System.getProperty(String key).

Table 5.1. Standard system properties

Key

Explanation

Value

microedition.platform

Name of the host platform or device

(implementation-dependent)

microedition.encoding

Default character encoding

"ISO-8859-1"

microedition.configuration

Name and version of the supported configuration

"CLDC-1.1"

microedition.profiles

Names of the supported profiles

(implementation-dependent)

Property microedition.encoding describes the default character encoding name. This information is used by the system to find the correct class for the default character encoding for supporting internationalization. Property microedition.platform characterizes the host platform or device. Property microedition.configuration describes the current J2ME configuration and version, and property microedition.profiles defines a string containing the names of the supported profiles, separated by blanks.

Note that the set of properties defined above can be extended by J2ME profile specifications or device manufacturers. For instance, the MIDP Specification defines additional properties not included in Table 5.1. The set of system properties defined by the Mobile Information Device Profile can be found in Section 20.2, "System Properties."

Manufacturer-specific property definitions are prefixed with the same package name that the manufacturer-specific classes use (such as "com.companyname.propertyname"). The "microedition" namespace, as well as the "java" and "javax" namespaces, are reserved and may only be extended by official J2ME configurations, profiles, or optional packages.


5.3 CLDC-Specific Classes

This section contains a description of the Generic Connection framework for supporting input/output and networking in a generalized, extensible fashion. The Generic Connection framework provides a coherent way to access and organize data in a resource-constrained environment.

5.3.1 Background and Motivation

The class libraries included in Java 2 Standard Edition and Java 2 Enterprise Edition provide a rich set of functionality for handling input and output access to storage and networking systems. For instance, in JDK 1.3.1, the package java.io contained 59 regular classes and interfaces, and 16 exception classes. The package java.net of JDK 1.3.1 consisted of 31 regular classes and interfaces, and 8 exception classes. It is difficult to make all this functionality fit in a small device with only a few hundred kilobytes of total memory budget. Furthermore, a significant part of the standard I/O and networking functionality is not directly applicable to today's small devices, which often do not have TCP/IP support, or which commonly need to support specific types of connections such as Infrared or Bluetooth.

In general, the requirements for the networking and storage libraries vary significantly from one resource-constrained device to another. For instance, device manufacturers who are dealing with packet-switched networks typically want datagram-based communication mechanisms, while those dealing with circuit-switched networks require stream-based connections. Due to strict memory limitations, manufacturers supporting certain kinds of networking capabilities generally do not want to support any other mechanisms. All this makes the design of the networking facilities for CLDC very challenging, especially since J2ME configurations are not allowed to define optional features. Also, the presence of multiple networking mechanisms and protocols is potentially very confusing to the application programmer, especially if the programmer has to deal with low-level protocol issues.

5.3.2 The Generic Connection Framework

The challenges presented above have led to the generalization of the J2SE networking and I/O classes. The high-level goal for this generalized design is to be a precise functional subset of J2SE classes, which can easily map to common low-level hardware or to any J2SE implementation, but with better extensibility, flexibility, and coherence in supporting new devices and protocols.

The general idea is illustrated below. Instead of using a collection of different kinds of abstractions for different forms of communication, a set of related abstractions are used at the application programming level.

General form
Connector.open("<protocol>:<address>;<parameters>");

Note

These examples are provided for illustration only. CLDC itself does not define any protocol implementations (see Section 5.3.3, "No Network Protocol Implementations Defined in CLDC"). It is not expected that a particular J2ME profile would provide support for all these kinds of connections. J2ME profiles may also support protocols not shown below.

HTTP
Connector.open("http://www.sun.com");
Sockets
Connector.open("socket://129.144.111.222:2800");
Communication ports
Connector.open("comm:com0;baudrate=9600");
Datagrams
Connector.open("datagram://129.144.111.222:2800");

All connections are created by calling the static method open of the class javax.microedition.io.Connector. If successful, this method will return an object that implements one of the javax.microedition.io.Connection interfaces shown in Figure 5.1. The Connector.open method takes a String parameter in the general form:

Connector.open("<protocol>:<address>;<parameters>");
Figure 5.1. Connection interface hierarchy

The syntax of the Connector.open parameter strings should generally follow the Uniform Resource Indicator (URI) syntax as defined in the IETF standard RFC2396 (http://www.ietf.org/rfc/rfc2396.txt).

A central objective of this design is to isolate, as much as possible, the differences between the use of one protocol and another into a string characterizing the type of connection. This string is the parameter to the method Connector.open. A key benefit of this approach is that the bulk of the application code stays the same regardless of the kind of connection that is used. This is different from traditional implementations in which the abstractions and data types used in applications often change dramatically when changing from one form of communication to another.

The binding of protocols to a J2ME program is done at run time. At the implementation level, the string (up to the first occurrence of ':') that is provided as the parameter to the method Connector.open instructs the system to obtain the desired protocol implementation from a location where all the protocol implementations are stored. It is this late binding mechanism that permits a program to dynamically adapt to use different protocols at run time. Conceptually this is identical to the relationship between application programs and device drivers on a personal computer or workstation.

In order to read and write data to and from Generic Connections that have been opened using the Connector.open method, a number of input and output stream classes are provided. The input and output stream classes supported by CLDC are listed in Section 5.2.4, "Input/Output Classes." J2ME profiles may provide additional stream classes as necessary.

5.3.3 No Network Protocol Implementations Defined in CLDC

The Generic Connection framework included in CLDC does not specify the actual supported network protocols or mandate implementations of any specific networking protocols. The CLDC Specification provides an extensible framework that can be customized by J2ME profiles such as MIDP to support those protocols that specific device categories might need. The actual implementations and decisions regarding supported protocols must be made at the profile level. Refer to Chapter 15, "MIDP Networking and Serial Communications" and Chapter 16, "Secure Networking" for details on the MIDP networking libraries. Those chapters include a number of sample applications that illustrate the use of the Generic Connection framework.

5.3.4 Summary of the Generic Connection Interfaces

Connections to different types of devices will need to exhibit different forms of behavior. A file, for instance, can be renamed, but no similar operation exists for a TCP/IP socket. The Generic Connection framework reflects these different capabilities, ensuring that operations that are logically the same share the same API.

The Generic Connection framework is implemented using a hierarchy of Connection interfaces (located in package javax.microedition.io) that group together classes of protocols with the same semantics. This hierarchy consists of seven interfaces shown earlier in Figure 5.1. Additionally, there is the Connector class, one exception class (ConnectionNotFoundException), one other interface, and a number of data stream classes for reading and writing data. At the implementation level, a minimum of one class is needed for implementing each supported protocol. Often, each protocol implementation class contains simply a number of wrapper functions that call the native functions of the underlying host operating system.

There are six basic interface types that are addressed by the Generic Connection framework:

  • A basic serial input device

  • A basic serial output device

  • A datagram-oriented communications device

  • A circuit-oriented communications device

  • A notification mechanism to inform a server of client-server connections

  • A basic Web server connection

The collection of Connection interfaces forms a hierarchy that becomes progressively more capable as the hierarchy progresses from the root Connection interface. This arrangement allows J2ME profile designers or application programmers to choose the optimal level of cross-protocol portability for the libraries and applications they are designing.

The Connection interface hierarchy is illustrated in Figure 5.1. A brief summary of each interface class is provided below. For a definitive reference on the Connection interfaces, refer to the documentation that is provided as part of the CLDC reference implementation.

Interface Connection

This is the most basic connection type that can only be opened and closed. The open method is not included in the interface because connections are always opened using the static open method of the Connector class.

Methods:
public void close() throws IOException;
Interface InputConnection

This connection type represents a device from which data can be read. The openInputStream method of this interface will return an InputStream for the connection. The openDataInputStream method of this interface will return a DataInputStream for the connection.

Methods:
public InputStream openInputStream() throws IOException;
public DataInputStream openDataInputStream() throws IOException;
Interface OutputConnection

This connection type represents a device to which data can be written. The openOutputStream method of this interface will return an OutputStream for the connection. The openDataOutputStream method of this interface will return a DataOutputStream for the connection.

Methods:
public OutputStream openOutputStream() throws IOException;
public DataOutputStream openDataOutputStream() throws IOException;
Interface StreamConnection

This connection type combines the InputConnection and OutputConnection interfaces. It forms a logical starting point for classes that implement two-way communication interfaces.

Interface ContentConnection

This connection type is a sub-interface of StreamConnection. It provides access to some of the most basic metadata information provided by HTTP connections.

Methods:
public String getType();
public String getEncoding();
public long getLength();
Interface StreamConnectionNotifier

This connection type is used when waiting for a connection to be established. The acceptAndOpen method of this interface will block until a client program makes a connection. The method returns a StreamConnection on which a communications link has been established. Like all connections, the returned StreamConnection must be closed when it is no longer needed.

Methods:
public StreamConnection acceptAndOpen() throws IOException;
Interface DatagramConnection

This connection type represents a datagram endpoint. In common with the J2SE datagram interface, the address used for opening the connection is the endpoint at which datagrams are received. The destination for datagrams to be sent is placed in the datagram object itself. There is no address object in this API. Instead, a string is used that allows the addressing to be abstracted in a similar way as in the Connection interface design.

Methods:
public int getMaximumLength() throws IOException;
public int getNominalLength() throws IOException;
public void send(Datagram datagram) throws IOException;
public void receive(Datagram datagram) throws IOException;
public Datagram newDatagram(int size) throws IOException;
public Datagram newDatagram(int size, String addr)
       throws IOException;
public Datagram newDatagram(byte[] buf, int size)
       throws IOException;
public Datagram newDatagram(byte[] buf, int size, String addr)
       throws IOException;

This DatagramConnection interface requires a data type called Datagram that is used to contain the data buffer and the address associated with it. The Datagram interface contains a useful set of access methods with which data can be placed into or extracted from the datagram buffer. These access methods conform to the DataInput and DataOutput interfaces, meaning that the datagram object also behaves like a stream. A current position is maintained in the datagram. This is automatically reset to the start of the datagram buffer after a read operation is performed.

Refer to Chapter 15, "MIDP Networking and Serial Communications," and Chapter 16, "Secure Networking," for sample applications that illustrate the use of the Generic Connection framework and the interfaces listed above.


5.4 New for CLDC 1.1

The following list summarizes the Java library changes between CLDC Specification versions 1.0 and 1.1. For details, refer to "CLDC Almanac" on page 359.

  • Classes Float and Double have been added.

  • The following methods have been added to other library classes to handle floating point values:

    • java.lang.Integer.doubleValue()

    • java.lang.Integer.floatValue()

    • java.lang.Long.doubleValue()

    • java.lang.Long.floatValue()

    • java.lang.Math.abs(double a)

    • java.lang.Math.abs(float a)

    • java.lang.Math.max(double a, double b)

    • java.lang.Math.max(float a, float b)

    • java.lang.Math.min(double a, double b)

    • java.lang.Math.min(float a, float b)

    • java.lang.Math.ceil(double a)

    • java.lang.Math.floor(double a)

    • java.lang.Math.sin(double a)

    • java.lang.Math.cos(double a)

    • java.lang.Math.tan(double a)

    • java.lang.Math.sqrt(double a)

    • java.lang.Math.toDegrees(double angrad)

    • java.lang.Math.toRadians(double angrad)

    • java.lang.String.valueOf(double d)

    • java.lang.String.valueOf(float f)

    • java.lang.StringBuffer.append(double d)

    • java.lang.StringBuffer.append(float f)

    • java.lang.StringBuffer.insert(int offset, double d)

    • java.lang.StringBuffer.insert(int offset, float f)

    • java.io.DataInput.readDouble()

    • java.io.DataInput.readFloat()

    • java.io.DataInputStream.readDouble()

    • java.io.DataInputStream.readFloat()

    • java.io.DataOutput.writeDouble(double v)

    • java.io.DataOutput.writeFloat(float v)

    • java.io.DataOutputStream.writeDouble(double v)

    • java.io.DataOutputStream.writeFloat(float f)

    • java.io.PrintStream.print(double d)

    • java.io.PrintStream.print(float f)

    • java.io.PrintStream.println(double d)

    • java.io.PrintStream.println(float f)

    • java.util.Random.nextDouble()

    • java.util.Random.nextFloat()

  • The following fields have been added to support floating point calculations:

    • java.lang.Math.E

    • java.lang.Math.PI

  • Classes java.lang.ref.Reference and java.lang.ref.WeakReference have been added.

  • Classes java.util.Calendar, java.util.Date and java.util.TimeZone have been redesigned to be more J2SE-compliant by adding a number of fields and methods.

  • One new error class, NoClassDefFoundError, has been added.

  • Class Thread has the following new methods and constructors:

    • Thread.getName()

    • Thread.interrupt()

    • Thread(Runnable Target, String name)

    • Thread(String name)

  • In addition, the following fields and methods have been added:

    • java.lang.Boolean.TRUE and java.lang.Boolean.FALSE

    • java.lang.String.intern()

    • java.lang.String.equalsIgnoreCase()

    • java.util.Date.toString()

    • java.util.Random.nextInt(int n)


Chapter 6. Mobile Information Device Profile

The Mobile Information Device Profile (MIDP) for the Java™ 2 Platform, Micro Edition (J2ME™) is an architecture and a set of Java libraries that create an open application environment for small, resource-constrained mobile information devices, or MIDs. Typical examples of MIDP target devices include cellular phones, two-way pagers, and wireless personal organizers. As summarized in Chapter 3, MIDP 2.0 devices typically fulfill the following minimum requirements:

  • Memory:

    • 256 kilobytes of non-volatile memory for the MIDP components

    • 8 kilobytes of non-volatile memory for application-created persistent data

    • 128 kilobytes of volatile memory for the virtual machine runtime (for example, the object heap)

  • Display:

    • Screen-size: 96x54

    • Display depth: 1-bit

    • Pixel shape (aspect ratio): approximately 1:1

  • Input:

    • One or more of the following user-input mechanisms:

      • "one-handed keypad"

      • "two-handed keyboard"

      • touch screen

  • Networking:

    • Two-way, wireless, possibly intermittent, with limited bandwidth

  • Sound:

    • The ability to play tones, either via dedicated hardware or via software algorithm

Note that since MIDP runs on top of the J2ME Connected Limited Device Configuration (CLDC), the memory requirements of CLDC must be added to the minimum numbers shown above.


6.1 MIDP Expert Groups

6.1.1 MIDP 1.0 Expert Group

The MIDP Specification version 1.0 was produced by the Mobile Information Device Profile Expert Group (MIDPEG) as part of the Java Community Process (JCP) standardization effort JSR 37. The following 22 companies, listed in alphabetical order, were members of the MIDP 1.0 standardization effort:

• America Online | • DDI | • Ericsson
• Espial Group | • Fujitsu | • Hitachi
• J-Phone | • Matsushita | • Mitsubishi
• Motorola | • NEC | • Nokia
• NTT DoCoMo | • Palm Computing | • RIM
• Samsung | • Sharp | • Siemens
• Sony | • Sun Microsystems | • Symbian
• Telcordia Technologies |  |

6.1.2 MIDP 2.0 Expert Group

The MIDP Specification version 2.0 was produced as part of the Java Community Process (JCP) standardization effort JSR 118. More than 120 people (the largest expert group ever created in the Java Community Process) were members of the MIDP 2.0 expert group.

The expert group included people from the following 49 companies (alphabetical):

• 4thpass Inc. | • AGEA Corporation | • Alcatel
• Aplix Corporation | • AromaSoft Corp | • Baltimore Technologies
• CELLon France | • Distributed Systems Technology Centre | • Elata PLC
• Esmertec | • Espial Group | • France Telecom / Orange
• Fujitsu Limited | • German Aerospace Center (DLR), Institute of Communications and Navigation | • Hitachi Ltd. / Digital Media Group
• In Fusio | • J-PhoneEast Co. Ltd | • Logical Mobile Networks
• Mitsubishi Electric Corp | • Mobile Scope AG | • Mobilitec
• Motorola | • NEC Corporation | • Nextel Communications
• Nokia | • NTT DoCoMo | • Omnitel Pronto Italia S.p.A
• One 2 One | • Openwave Systems Inc. | • Orange (UK)
• Palm | • Philips Consumer Communications | • Philips Semiconductors
• Research In Motion (RIM) | • Samsung Electronics Co., Ltd | • Sharp Labs
• Siemens AG | • Siemens ICM | • Smart Fusion
• Sony Ericsson Mobile Communications | • Sun Microsystems | • Symbian Ltd.
• Telefónica Móviles España | • Vaultus Inc. | • Veloxsoft Inc.
• Vodafone Global Platform & Internet Services | • Vodafone Group Services Limited | • Vodafone Multimedia
• Zucotto Wireless |  |

In addition, the following nine individuals were members of the MIDP 2.0 expert group:

• Fabio Ciucci | • Wai Kit Tony Fung | • Neil Katin
• Glen Cordrey | • David Hook | • Steve Ma
• Jon Eaves | • Myank Jain | • Ravi Kumar Reddy


6.2 Areas Covered by the MIDP Specification

The Mobile Information Device Profile Specification extends the functionality defined by the Connected, Limited Device Configuration (CLDC) Specification. The MIDP Specification defines a set of APIs that add a minimum set of capabilities that are common to various kinds of mobile information devices. The MIDP Specification version 2.0 extends the capabilities of the original MIDP Specification version 1.0 while retaining full backward compatibility. As already summarized earlier in Section 3.5.2, "Scope of MIDP," the specific areas covered by the MIDP Specification version 2.0 include:

  • application model (that is, defining the semantics of a MIDP application and how the application is controlled),

  • user interface support (Limited Capability Device User Interface, LCDUI),

  • networking support (based on the HTTP protocol and the Generic Connection framework introduced by CLDC),

  • persistent storage support (Record Management System, RMS),

  • sounds,

  • 2D games,

  • end-to-end security through HTTPS and secure sockets,

  • MIDlet signing model for added security,

  • application delivery and installation, and

  • miscellaneous classes such as timers and exceptions.

In addition to these areas, the MIDP Specification defines an extension of the CLDC application model that allows for the execution and communication of applications called MIDlets. A MIDlet is the basic unit of execution in MIDP. One or more MIDlets packaged together are called a MIDlet suite. The MIDP application model and each of the areas mentioned above are discussed in detail in the subsequent chapters of this book. The concept of a MIDlet suite is discussed in detail in Section 19.1, "MIDlet Suites."


Chapter 7. MIDP Application Model

Due to the strict memory constraints and the requirement to support application interaction and data sharing within related applications, the Mobile Information Device Profile does not support the familiar Applet programming model introduced by the Java™ 2 Platform, Standard Edition (J2SE™). Rather, MIDP introduces a new application model that is better suited for the specific needs of small, resource-constrained devices. This application model is integrated closely with the MIDP user interface libraries (see Chapters 8–11), and it replaces the simple, command line-oriented application model supported by the Connected, Limited Device Configuration.


7.1 MIDlets

In MIDP, the basic unit of execution is a MIDlet. A MIDlet is a class that extends the class javax.microedition.midlet.MIDlet and implements a few methods—including startApp, pauseApp, and destroyApp—to define the key behavior of the application.

As an example of programming with the MIDP application model, consider the following program that implements one of the simplest MIDlets possible: the canonical "Hello World" application.

package examples;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class HelloWorld extends MIDlet implements CommandListener {
    private Command exitCommand;
    private TextBox tb;

    // Constructor of the HelloWorld class
    public HelloWorld() {
        // Create "Exit" Command so the user can exit the MIDlet
        exitCommand = new Command("Exit", Command.EXIT, 1);

        // Create TextBox in which the output will be displayed
        tb = new TextBox("Hello MIDlet", "Hello, World!", 15, 0);

        // Add the Command and set the CommandListener
        tb.addCommand(exitCommand);
        tb.setCommandListener(this);

        // Set our TextBox as the current screen
        Display.getDisplay(this).setCurrent(tb);
    }

    // Called by the system when the MIDlet is started
    // for the first time, and when it is resumed after
    // being paused.
    protected void startApp() {}

    // Called by the system when the MIDlet is paused.
    // In this application, there is no need to do anything
    // when we are paused.
    protected void pauseApp() {}

    // Called when the MIDlet is destroyed.  In this case,
    // there is no need to do anything when we are destroyed.
    protected void destroyApp(boolean force) {}

    // This method is called automatically by the system
    // in response to a user activating one of the Commands.
    public void commandAction(Command c, Displayable d) {
        // Upon receiving the "Exit" Command, destroy ourselves
        if (c == exitCommand) {
            destroyApp(false);
            notifyDestroyed();
        }
    }
}

The output of this simple MIDlet, when run on a MIDP device emulator, is shown in the figure on the right. In the figure, the MIDlet's startApp method has just completed its execution. Pressing the "Exit" button on the phone's keypad would trigger the delivery of the exitCommand to the commandAction method which invokes the destroyApp and notifyDestroyed methods.

In this example, there are a few key things that are common to all MIDlets, no matter how simple or complex the applications are.

First, HelloWorld extends the class javax.microedition.midlet.MIDlet. Second, like every Java class, a MIDlet can have a constructor. In the MIDP application model, the system (see Section 19.2, "MIDP System Software") calls the no-argument constructor of a MIDlet exactly once to instantiate the MIDlet. The functions that need to be performed in the constructor depends on how the MIDlet is written, but in general, any operations that must be performed only once when the application is launched should be placed in the constructor.

If no such functionality is required by the MIDlet, then there is no need to provide a constructor. Care should be taken in the constructor to catch any exceptions and handle them gracefully because an uncaught exception will prevent the MIDlet from being created and the application will not be able to run.

Third, the application's MIDlet class must implement the abstract lifecycle methods of class javax.microedition.midlet.MIDlet so the application can respond to state changes. These methods are: startApp, pauseApp, and destroyApp. The startApp method is used for starting or restarting a MIDlet. The pauseApp method is called by the system to ask a MIDlet to "pause." The destroyApp method is called by the system when the MIDlet is about to be destroyed; it can also be called indirectly by the MIDlet itself in order to clean up before exiting.

Taken as a whole, the startApp, pauseApp, and destroyApp methods represent a state machine that controls the life cycle of the MIDlet. This life cycle, as well as the recommended practices for defining the startApp, pauseApp, and destroyApp methods, are described in more detail in Section 7.1.1, "MIDlet States."

Fourth, the application also implements the CommandListener interface (see method CommandAction) so that the application can respond to user actions. This interface, along with the TextBox, Command, and Display classes, is part of the javax.microedition.lcdui package that will be discussed in detail later in this book.

7.1.1 MIDlet States

MIDlets have a well-defined life cycle. A MIDlet is typically started (for example, when the user launches it from a screen of applications available to be run), it interacts with the user through its graphical user interface, and is then stopped (for example, when the user chooses a button labelled "Exit").

In general, during the lifetime of a MIDlet, it may be in one of three distinct states, with well-defined rules that govern the transitions between these states (see Figure 7.1):

  • Paused: A MIDlet is in the Paused state when it has just been constructed and has not yet entered its startApp method. It can also be in the Paused state as a result of the pauseApp or the notifyPaused methods (see below). When in the Paused state, a MIDlet should hold as few resources as possible. A MIDlet in the Paused state can receive asynchronous notifications, for example, from a timer firing (see Section 20.1, "Timer Support").

  • Active: A MIDlet is in the Active state upon entry to its startApp method. In addition, a MIDlet can transition from the Paused state to the Active state as the result of the resumeRequest method. While in the Active state, a MIDlet can allocate and hold all necessary resources for optimal execution.

  • Destroyed: A MIDlet is in the Destroyed state when it has returned from the destroyApp or notifyDestroyed methods. Once a MIDlet enters the Destroyed state, it cannot reenter any other state. The Destroyed state replaces the normal convention of an application calling the System.exit method to terminate. A MIDlet cannot call the System.exit method, since doing so will throw a java.lang.SecurityException (see Section 20.4, "Exiting a MIDlet.")

Figure 7.1. MIDlet states and state transitions

The MIDlet state transitions can be triggered either by the MIDP system itself or by requests from the application. Below we summarize how the MIDP system initiates these state transitions by calling methods on the MIDlet. Note that with the exception of startApp, which completes the state change to Active upon the origination of the call, all other state changes complete after the associated methods return to the caller.

The MIDlet's constructor is invoked to create an instance of the MIDlet. A MIDlet is in the Paused state when it has just been constructed and has not yet entered its startApp method. If defined, a constructor must be public or protected and have no arguments. The MIDP system calls the constructor exactly once to instantiate the MIDlet. (See Section 19.2, "MIDP System Software" for an explanation of the MIDP system.) In general, MIDlet programmers should use the constructor for any initialization operations that must be performed only once and can be performed when the application is launched. If a MIDlet has no such operations, then the MIDlet programmer need not provide a constructor. The initialization done within the constructor should be brief. Lengthy delays caused by long operations such as network access should be performed in the background or delayed until the user can be informed appropriately.

The startApp method is called by the system to move a MIDlet into the Active state for the first time and also when a MIDlet is being resumed from the Paused state. When a MIDlet enters its startApp method, it is in the Active state. An important note: Beginning MIDlet programmers are often tempted to treat startApp as equivalent to the main method, and thus combine MIDlet initialization and main-line processing in the startApp method. In general this is not a good idea, since the startApp method may be called more than once: one time initially, and then once per each transition from Paused to Active state.

The pauseApp method is called to move the MIDlet into the Paused state. During the normal operation of a mobile device, the system might run into situations where it is necessary to suspend or pause some of the MIDlets on the device. The most common example is when a device is running low on memory. In order to reclaim memory, the system may call the pauseApp method of all the Active MIDlets. When the pauseApp method of a MIDlet is called, the MIDlet should release as much of its resources as possible and become quiescent. Note that the system does not actually try to force any specific behavior on a MIDlet in a Paused state, so it is possible for an ill-behaved MIDlet to ignore this request. However, if such a situation occurs, the system may forcibly terminate the MIDlet or even the virtual machine itself, especially in a low-memory situation.

The destroyApp method is the normal way the system terminates a MIDlet. The destroyApp method has one boolean parameter that indicates whether or not the request is unconditional. If the request is not unconditional (that is, the boolean parameter is false), then the MIDlet may request a "stay of execution" by throwing a MIDletStateChangeException. In this case, if the system is able to honor the request, the MIDlet may continue in its current state (Paused or Active). If, on the other hand, the request is unconditional, then the MIDlet should give up its resources, save any persistent data it might be caching, and return. Upon normal return from this method, the MIDlet enters the Destroyed state and can be reclaimed by the system.

While the MIDP system is the primary instigator of MIDlet state changes, a MIDlet application programmer can also request state changes using the resumeRequest, notifyPaused, and notifyDestroyed methods in the MIDlet class.

The resumeRequest method can be called by a Paused MIDlet to indicate that it wishes to reenter the Active state. The primary scenario for this call is when a Paused MIDlet handles a timer expiration and needs to resume processing.

The notifyPaused method is provided to allow a MIDlet to signal to the system that it has voluntarily entered the Paused state (that is, it has released its resources and is now quiescent). An example use case for this call is a time-based MIDlet that sets timers and has nothing to do until those timers expire.

The notifyDestroyed method can be called by the MIDlet to tell the system that the MIDlet has released all its resources and has saved any cached data to persistent storage. Note that the destroyApp method of a MIDlet will not be called by the system as a result of invoking this method. The MIDlet may reasonably call destroyApp itself to do the same cleanup as if the system called it.

7.1.2 Using the startApp, pauseApp, and destroyApp Methods

Using the startApp method

The startApp method is used for starting or restarting a MIDlet. This method may be called by the system under different circumstances (see Section 7.1.1, "MIDlet States"), but its purpose is to acquire or reacquire resources needed by the MIDlet and to prepare the MIDlet to handle events such as user input and timers. Note that the startApp method may be called more than once—once to start execution for the first time and again for every time the MIDlet is "resumed"; therefore, a startApp method should be written so that it can be called under these different circumstances.

The startApp method can "fail" in two ways: with a transient failure or a non-transient failure. A transient failure is one that might have to do with a certain point in time (such as a lack of resources, network connectivity, and so forth). Since this type of error may not be fatal, a MIDlet can tell the system that it would like to try to initialize later by throwing a javax.microedition.midlet.MIDletStateChangeException. A non-transient failure is one that is caused by any other unexpected and uncaught runtime error. In this case, if the runtime error is not caught by the startApp method, it is propagated back to the system that will destroy the MIDlet immediately and call the MIDlet's destroyApp method.

A robust startApp method should distinguish between transient and non-transient exceptions and respond accordingly, as illustrated in the following code fragment:

void startApp() throws MIDletStateChangeException {
    CommConnection port = null;
    try {
        port = (CommConnection)Connector.open(...);
        ...
    } catch (IOException ioe) {
        // Transient failure: could not connect to the serial port
        throw new MIDletStateChangeException(
                      "Serial port not available");
    } catch (Exception e) {
        // Non-transient failure: can either catch this and
        // exit here, or let the exception propagate back to
        // the system
        destroyApp(true);
        notifyDestroyed();
    }
}
Using the pauseApp method

The pauseApp method is called by the system to ask a MIDlet to "pause." The definition of what pause means is discussed in Section 7.1.1, "MIDlet States," but in general, the pauseApp method works in conjunction with the startApp method to release as many resources as possible so that there is more memory and/or resources available to other MIDlets or native applications. The use of the pauseApp method is illustrated in the following code fragment:

int[] runTimeArray = null;
void startApp() {
    // Coming from a paused state; initialize data
    runTimeArray = new int[200];
    ...
}

void pauseApp() {
    // Set runTimeArray to null so that it is
    // a candidate for garbage collection
    runTimeArray = null;
    ...
}
Using the destroyApp method

The last method that a MIDlet must implement is the destroyApp method. This method is called by the system when the MIDlet is about to be destroyed; it can also be called indirectly by the MIDlet itself in order to clean up before exiting. In either case, the destroyApp method should be written so that it performs all the necessary cleanup operations to release all the resources (that is, close the graphical user interface components, network connections, and database records) that the application had allocated during its execution. The following code fragment provides a simple example:

RecordStore rs = null;
void startApp() {
    ...
    rs = RecordStore.openRecordStore(...);
    ...
}
void destroyApp(boolean force) {
    if (rs != null) {
        // Make sure all records are written to storage
        // and close the record store
        ...
    }
}

7.1.3 Application Lifecycle and the User Interface API

Since the user interface components play a key role in a MIDP application, the initialization of the user interface components is one of the first tasks for the application when a MIDlet is instantiated.

The application management software of a MIDP system assumes that the application is well-behaved with respect to the MIDlet events. The paragraphs below summarize what a well-behaved MIDlet is expected to do when each of its lifecycle methods is called.

The constructor initializes the application state. The method can access the Display for the MIDlet by calling the Display.getDisplay method. It can create screens and objects needed when the application is started. It does not have access to the user interface, so information or alerts cannot be shown. The method can set the first screen to be shown to the user. The initialization performed should be brief; lengthy delays caused by long operations such as network access should be performed in the background or delayed until the user can be informed appropriately.

The application manager calls the startApp method to notify the MIDlet that it has been started (or resumed after being paused) and makes the screen set with Display.setCurrent visible when startApp returns. Note that startApp can be called several times if pauseApp is called in between. This means that objects or resources freed by pauseApp might need to be recreated.

When the pauseApp method is called the application should release any unneeded resources that can be re-initialized if the application is restarted. The application should pause its threads unless they are needed for background activities. Also, if the application should restart with another screen when the application is reactivated, the new screen should be set with Display.setCurrent.

Since CLDC does not provide guaranteed real-time behavior, the system is not required to use the Paused state to manage the interaction of the real-time portions of the phone and the Java environment. Consider, for example, the case where the virtual machine is running on a cellular phone, and the phone receives a call. In this scenario, the real-time operating system on the phone might suspend the virtual machine altogether rather than cycle the MIDlets to the Paused state.

When the destroyApp method is called the application's user interface will no longer be displayed. Still, the application should close all active resources, stop any active threads, and unregister or free any objects that would not be freed by a normal garbage collection cycle.


7.2 MIDlet Suites

When MIDlets are delivered to devices for execution, they are packaged in a MIDlet suite. MIDlet suites provide a controlled way of downloading multiple MIDlets onto a device as well as support controlled sharing of data and resources between multiple, possibly simultaneously running MIDlets. MIDlet suites will be discussed in detail in Chapter 19, "MIDlet Deployment."


7.3 New for MIDP 2.0

The MIDP application model has not changed since MIDP 1.0. However, the interactions with the user interface and the suggested application actions that are performed in these methods are now more precisely defined. By limiting the complexity of functions performed in these methods, the application can be more responsive to both system requests and user actions.


Chapter 8. MIDP User Interface Libraries

In light of the wide variations in cellular phones and other MIDP target devices, the requirements for user interface support are very challenging. MIDP target devices differ from desktop systems in many ways, especially in how the user interacts with them. The following UI-related requirements were seen as important when the user interface library of the MIDP Specification was designed:

  • The devices and applications should be useful to users who are not necessarily experts in using computers.

  • The devices and applications should be useful in situations where the user cannot pay full attention to the application. For example, many cellular phones and other wireless devices are commonly operated with one hand while the user is walking, cooking, fishing, and so forth.

  • The form factors and user interface concepts of MIDP target devices vary considerably between devices, especially compared to desktop systems. For example, display sizes are much smaller, and input devices are much more limited or at least different. Most mobile devices have only numeric keypads, and few have pointing devices such as pen-operated touch screens.

  • The Java applications for mobile information devices should have user interfaces that are consistent with the native applications so that the user finds them intuitive to use.

Given these requirements and the capabilities of devices that implement the MIDP (see Section 3.2, "Target Devices"), a dedicated user interface toolkit is provided in MIDP in the javax.microedition.lcdui package.


8.1 MIDP UI Compared to Desktop AWT

The differences between mobile devices and desktop computers are evident when comparing the designs of the MIDP lcdui with the Abstract Windowing Toolkit (AWT) of the JavaTM 2 Platform, Standard Edition.

AWT was designed and optimized for desktop computers. The assumptions that are appropriate for desktop computers are not appropriate for mobile devices. For example, when a user interacts with AWT, event objects are created dynamically. These objects are short-lived and exist only until each associated event is processed by the system. The event object then becomes garbage and must be reclaimed by the garbage collector of the Java virtual machine. The limited CPU and memory subsystems of a mobile information device (MID) typically cannot afford the overhead of unnecessary garbage objects. To limit the creation of such objects, lcdui events are simply method calls that pass the event parameters directly as the parameters of the method.

AWT also assumes certain desktop environment specific user interaction models. For instance, the component set of AWT was designed to work with a pointing device such as a mouse or pen. As mentioned earlier, this assumption is valid only for a small subset of MIDs, since most of the MIDP target devices have just a keypad for user input. The MIDP user interface API uses a layer of abstraction to separate applications from concrete input methods used in different devices. For example, a MIDP device with touch input allows the user to use this input method on high-level user interface components but it is not visible to applications. The different concrete input methods are transparent to the application code.

AWT has extensive support for window management, such as overlapping windows, window resizing, and so forth. In contrast, MIDP target devices have small displays that are not large enough for multiple overlapping windows. The lcdui API of MIDP has no window management capabilities. A lcdui user interface is constructed using a set of Displayables. This displayable model and the class structure of user interface are described in the next section.


8.2 Structure of the MIDP User Interface API

The following sections provide an overview to the MIDP user interface API (javax.microedition.lcdui). The remainder of this chapter and the following two chapters concentrate on the high-level parts of the API. The low-level user interface API features are detailed in Chapter 11, "MIDP Low-Level User Interface Libraries."

The separation of high-level and low-level API is often not very clear-cut. There are many classes that are used both in low-level and high-level APIs. For example, classes Image and Font are used both in high-level Screen components and low-level graphics drawing. Also, in MIDP 2.0 the new CustomItem class makes it possible to mix low-level graphics and high-level components within a Form object.

MIDP 2.0 also includes a new game-specific API provided in javax.microedition.lcdui.game package. The MIDP 2.0 Game API is discussed in Chapter 12.

8.2.1 Displayable Model

The central abstraction of the MIDP user interface is class Displayable. Class Displayable helps organize the user interface into manageable pieces. This results in user interfaces that are easy to use and learn. Each MIDP application has a Display on which a single Displayable object is shown. The application sets and resets the current Displayable object on the Display for each step of the task, based on user interactions. The user tasks (interactions with the user interface) are implemented using Command objects. The application is notified automatically when a Command is selected by the user. As a result of these notifications the application often changes the current Displayable to some other Displayable. The device software manages the sharing of the physical display between the native applications and the MIDP applications.

The rationale behind the displayable-oriented approach is based on the wide variations in display and keypad configurations found in MIDP devices. Each device provides a consistent look and feel by handling the component layout, painting, scrolling, and focus traversal. If an application needed to be aware of these details, portability would be difficult to achieve, and smooth integration with the look and feel of the device and its native applications would place a heavy burden on application developers.

There is a hierarchy of Displayable subclasses called Screens in the lcdui API. Each Screen is a functional user interface element that encapsulates device-specific graphics rendering and user input handling. Figure 8.1 shows the hierarchy of the user interface classes.

Figure 8.1. MIDP user interface class hierarchy (all classes not shown)

There are two types of Displayable subclasses:

  • Canvas: low-level objects that allow the application to provide the graphics and handle input

  • Screen: high-level objects that encapsulate complete user interface components (classes Alert, List, TextBox, or Form)

Any application may use combinations of Screens and Canvases to present an integrated user interface. For instance, in a game application, Lists and Forms can be used to select or configure the options of a game, while Canvas (or GameCanvas) can be used for the interactive game components.

The Command class is used for implementing the application specific operations. For example, the navigation between different application Displayables is implemented using Commands. Details of Commands are described in Section 8.5, "Commands."

8.2.2 Low-Level User Interface

The low-level user interface API for Canvas is designed for applications that need precise placement and control of graphic elements as well as access to low-level input events. Typical examples are a game board, a chart object, or a graph. Using the low-level user interface API, an application can

  • control what is drawn on the display,

  • handle primitive events such as key presses and releases, and

  • access concrete keys and other input devices.

Applications that are programmed with the low-level API can be portable if the application uses only the standard features; applications should stick to the platform-independent part of the low-level API whenever possible. This means that the applications should not directly assume the presence of any keys other than those defined in class Canvas. Also, applications should inquire about the size of the display and its color capabilities and adjust behavior accordingly. See Section 8.6.2, "Adaptation to Device-Specific User Interface Style."

The CustomItem class allows the application developer to use low-level graphics on a Form. CustomItem provides a way to mix both low-level and high-level components within a single Form. Painting using the CustomItem class is done similarly to painting to Canvas via the Graphics class.

The low-level API is described in detail in Chapter 11, "MIDP Low-Level User Interface Libraries," and in Chapter 12, "MIDP Game API."

8.2.3 High-Level User Interface

The high-level user interface API is designed for business applications whose client components run on mobile information devices. For these applications, portability across devices is important. To achieve such portability, the high-level user interface API employs a high level of abstraction and provides very little control over look and feel. This allows devices to use the native user interface look and feel for the high-level MIDP user interface API components. This means that when an application is written with the high-level API, its look and feel automatically uses the look and feel of the device in which the application is currently running. For the end users this provides seamless user interaction: the MIDP application works the same way as the other (native) applications on the device.

The high-level user interface components described in this section behave consistently with the in-built user interfaces and applications of a device. More specifically, when using the high-level API:

  • Drawing to the display is performed by the device's system software. Applications do not define the visual appearance (such as shape, color, and so forth) of the components.

  • Navigation, scrolling, and other primitive interactions with the user interface components are performed by the device. The application is not aware of these interactions.

  • Applications cannot access concrete input mechanisms, such as individual keys.

The high-level API is provided through the Screen classes, which are:

  • List: allows a selection from a predefined set of choices.

  • TextBox: is a plain text editor with controllable editing modes.

  • Alert: displays temporary messages or simple choice queries.

  • Form: is a more generic container that allows to display multiple, closely-related user interface elements called Items.

These different Screen classes are more thoroughly presented in Chapter 9, "MIDP High-Level User Interface – Screen."

The class Form is defined for cases where a screen with a single function is not sufficient. Class Form is designed to contain a small number of closely related user interface elements, or Items. For example, an application might have two TextFields, or a TextField and a simple ChoiceGroup. If all the Items of a Form do not fit on the screen, the implementation might make the Form scrollable, expand each Item automatically when the user edits it, or use a "pop up" representation. Each Form can contain a combination of the following Item subclasses:

  • StringItem, used for static text display, or as a button or hyperlink.

  • ImageItem, used for static image display, or as an image button or hyperlink.

  • TextField, used for textual input with constraints.

  • DateField, used for display or input of time and date values.

  • Gauge, used as a progress indicator or as a numeric input from a specific range.

  • ChoiceGroup, used for single or multiple selections from a set of elements.

  • CustomItem (MIDP 2.0), used to create application specific items; drawing is done with low-level Graphics API.

  • Spacer (MIDP 2.0), used to create empty spaces for layout purposes.

Although the Form class allows the creation of arbitrary combinations of components, developers should keep in mind the limited display size and make Forms simple and functional. Chapter 10, "MIDP High-Level User Interface – Form" discusses the various Form classes in detail.


8.3 Display

The Display class is the central controller of the display of a MIDP application. An application gets a Display instance by calling the static method getDisplay and by passing the MIDlet instance to the method:

Display midletDisplay = Display.getDisplay(myMIDlet);

When the Display instance is obtained, the application can change the Displayables presented on the device using the methods of the Display class. There are three methods in class Display that allow the application to set the current Displayable instance presented on the device display. The most commonly used method is:

public void setCurrent(Displayable nextDisplayable)

The two other methods are provided for more specialized use:

public void setCurrent(Alert alert, Displayable nextDisplayable)
public void setCurrentItem(Item item)

The first of these specialized methods sets an Alert to be displayed and also provides the Displayable that is presented after the Alert is dismissed. See Section 9.3, "Alert." The second of these specialized methods presents a specific Item attached to a Form instance. The Form that has the Item is set as the current displayable, and it is scrolled so that the Item becomes visible. Focus, if supported by device, moves to this Item.

8.3.1 Current Displayable

Technically, the methods just discussed set only the current displayable of class Display. During the lifecycle of the application the current Displayable never again is null after it has been initially set at application startup. The current Displayable is made visible by the device software referred to as application management software (AMS) in MIDP Specification (see Section 19.2, "MIDP System Software.") The current Displayable is visible when the application is in the foreground.

There often are, however, situations when the application management software moves the application to the background, and thus the current Displayable is not actually visible. The current Displayable does not change in these cases. Applications are commonly moved to background upon system events such as incoming calls in a phone device or upon certain other system notifications. When the application management software decides that the application can again be brought to the foreground, the current Displayable is simply made visible.

The application can determine whether a Displayable is visible on the display by calling the method isShown. In the case of Canvas and CustomItem, the showNotify and hideNotify methods are called when the component is made visible and is hidden, respectively. Applications need to override showNotify and hideNotify methods in Canvas or CustomItem subclasses to be able receive these notifications.

Some devices may have the capability to run multiple applications simultaneously. If multiple applications are actually running simultaneously, some of the applications are in background. For such devices there is a feature in class Display that allows the application to request to be sent to background. The method call setCurrent(null) does not set the current Displayable to null, but instead does the background request and the current Displayable remains unchanged. It should be noted that in many devices this request is simply ignored, but those that can support background applications may move the application to the background. The application management software decides which application should be presented if this request is honored. Similarly, for background applications, any non-null call to setCurrent methods is treated as a request to return the application to the foreground. Conversely, since the current Displayable is unchanged when an application is in the background, the method call d.setCurrent(d.getCurrent()) can be used to request a return to the foreground without changing the Displayable.

8.3.2 Screen Backlight and Device Vibrator

In MIDP 2.0, class Display has methods to control the screen backlight and vibrator often found in mobile devices:

public boolean vibrate(int duration)
public boolean flashBacklight(int duration)

Both methods take a parameter that indicates the duration of the action in milliseconds. These methods work only if there is a controllable backlight and vibrator present in a device. The methods return false if no such feature is available. Applications should use these methods with care, as they both consume battery significantly and may be irritating to some users or in specific situations. Devices commonly also have general native settings for turning off these features, in which case the methods also return false.

The Display class also includes methods for retrieving some device properties, such as the color capabilities of the device. See Section 8.6.2, "Adaptation to Device-Specific User Interface Style," for a more detailed discussion of these methods.


8.4 Displayables

Displayable objects are the views in which the application interaction takes place. Application-defined operations in Displayable objects are implemented using Commands. The device implementation provides additional operations based on displayable type, as will be discussed in Section 8.6.3, "Device-Provided Operations."

All Displayable objects have the following properties:

  • Zero or more Commands for application specific user operations on the Displayable

  • A CommandListener (set by the application with the method setCommandListener[1]) that gets notified when the user selects any of the Commands

    [1] Note that only a single CommandListener can be added because of the unicast listener model is used in the lcdui API.

  • A title[2] string (set with the setTitle method) that is presented to the user in a standard place, for example, as a header text for the Displayable

    [2] In MIDP Specification version 2.0, the title and Ticker properties were added to class Displayable, which means that they are also available in class Canvas. In MIDP 1.0, these properties were only available in the Screen classes.

  • A Ticker object (set with the setTicker method) that provides automatically scrolling text attached to the Displayable

Both the title and Ticker can be null, which means that no title text or Ticker is displayed. Depending on the user interface implementation of the device, the existence of a Ticker or title can consume space from the rest of the displayable content.

The application is responsible for providing the means for the user to progress through different Displayables. The transition from one Displayable to another is performed using the Commands that the application has added to the current Displayable. When user selects a command, the command listener of the Displayable is activated. The listener typically changes the Displayable by calling the method setCurrent of class Display.

A badly behaving application might set up a Displayable that has no Commands. This is allowed by the API, but is generally not useful. If this occurs, the user would have no means to move to another screen. Often a device provides the means for the user to request the application manager to kill such an erroneous application.

An application can also implement Displayable changes in Canvas as actions resulting from low-level events, such as key events. In addition, nothing prevents an application from automatically changing its Displayable, for example, using a timer or thread. A possible scenario for such usage is when an application wants to continue its execution from a progress bar view[3] after a long network transaction has finished. Generally these types of automatic displayable changes should be used with care.

[3] This kind of a view could be implemented, e.g., using an Alert (MIDP 2.0 only) or Form with a non-interactive Gauge item. These user interface structures are discussed later.

Displayable classes that form the high-level API are called Screens. The use of different Screens is described in Chapter 9, "MIDP High-Level User Interface – Screen." The Canvas class is the main displayable on graphic-intensive applications such as games. Canvas is also used for custom components when high-level Screen classes do not provide the necessary components. For example, a data grid or table could be implemented using the Canvas low-level drawing primitives. (See Section 11.5, "Drawing Primitives.")

8.4.1 Ticker

The Ticker class implements a "ticker-tape," a piece of text that runs continuously across the display. The direction and speed of scrolling are determined by the device. The ticker string scrolls continuously; that is, when the string finishes scrolling off the display, the ticker string starts over at the beginning of the string.

There is no API provided for starting and stopping the Ticker. Rather, the application model is that the Ticker is always scrolling continuously.

A Ticker can be added to any instance of Displayable with the method addTicker, and it can be removed with the method setTicker(null). Applications should not use Ticker on Alert screens because some devices present Alerts as pop-up dialogs that may not have space for the Ticker. The same Ticker may be shared by several Displayable objects.

Setting a Ticker often affects the size of the area available for contents of Displayable. For example, fewer elements may be visible on a List. This change in content size is especially important to note when a Ticker is used in a Canvas. If the available area changes, the application is notified via a call to the sizeChanged method. Also, the getHeight and getWidth methods of class Canvas report smaller sizes.

In a typical usage scenario, an application uses the same Ticker on all of its Displayables. When the application switches between two Displayables that have the same Ticker, the desirable consequence is for the Ticker to be displayed at the same location on the display and to continue scrolling its contents at the same position. This gives the illusion of the Ticker being attached to the display instead of separately to each Displayable.

Nothing prevents an application from using different Tickers on different sets of Displayables, or even a different one on each Displayable. For example, a Ticker can be added to a List and the Ticker can be running while the List is being presented.

Ticker ticker = new Ticker(
    "Special offer! Apples only"
    + " two gold coins per box.");
List list = new List("", List.IMPLICIT);
... // Add choices to the List
    // and set command listener
list.addCommand(okCommand);
list.addCommand(backCommand);
list.setTicker(ticker);
display.setCurrent(list);


8.5 Commands

Abstract Commands are the operations that the applications add to the user interface. Commands can be added to all Displayables, so they are part of the application when using both high-level or low-level API. The most common task for Commands is to provide users with a way to navigate between different Displayables of an application. Normally, if there are no Commands in a Displayable, the user has no way to proceed to other Displayables.

Commands are added to a Displayable using addCommand method. There is also removeCommand to remove already-added commands. This allows to dynamically change available operations within displayables.

When the user selects a Command from the user interface, the device calls the CommandListener's commandAction method and passes the Command object and the Displayable instance in which the Command was activated.

In the next sections, the idea of Command abstraction is described first. Then the proper use of Commands in applications is summarized.

8.5.1 Command Mapping to Device User Interface

Since the MIDP user interface API is highly abstract, it does not dictate any concrete user interaction technique such as softkeys,[4] buttons, or menus. An abstract command mechanism allows an application to adjust to the widely varying input mechanisms of MIDP target devices and also allows it to be unaware of device specifics, such as number of keys, key locations, and key bindings. Low-level user interactions such as traversal or scrolling are not visible to the application, which helps the devices implement the high-level components in very different user interface styles. This also leverages application portability between devices.

[4] Softkeys are very common in mobile devices. Softkey is a keypad key positioned near the device display so that there is an changeable label present on the display that indicates the operation associated with the softkey.

MIDP applications define Commands, and the implementation can provide user control over these with softkeys, buttons, menus, or whatever mechanisms are appropriate for the device. Generally, Commands may be implemented using any user interface construct that has the semantics for activating a single action.

Commands are added to a Displayable (Canvas or Screen) with the method addCommand of class Displayable. The Commands can also be removed with the removeCommand method. This allows, for example, the application to control which Commands are available at a given time, based on user interaction. Some Commands can be paired with others or presented only in certain situations or context.

Each command has a type and a priority. Command types and priorities allow the device to place the commands to match the native user interface style of the device, and the device might put certain types of commands in standard places. For example, the "Go back" operation might always be mapped to the right softkey in a user interface style of a device. The device may decide to map a command with the BACK type to the right softkey. The Command class allows the application to communicate the abstract semantics of an action associated with a Command to the device so that action placements that are standard for that device can be used.

However, the device does not provide any automatic behavior for the Command. The type of a Command is used only for mapping it onto the user interface. The actual behavior of a Command is always implemented by the application in a CommandListener, which is set by the application to the Displayable.

The mapping of Commands to concrete user interface constructs might also depend on the total number of commands. If an application uses more commands than can be mapped onto the available physical buttons on a particular device, the device may use an alternate human interface such as a menu. For example, the abstract commands that cannot be mapped onto physical buttons may be placed in a menu, and the label "Menu" can be mapped onto one of the programmable buttons.

8.5.2 Command Properties

Each Command object has a string label, a command type and a priority:

  • Label: The label strings are what the application requests to be shown to the user to represent this Command. A single Command can have two versions of labels: short and long. The long label is optional. The implementation decides whether the short or long version is appropriate for a given situation. For example, a device can choose to use a short version of a given Command near a softkey and the long version of the Command in a menu. The short label string should be as short as possible so that it consumes a minimum of screen real estate. The long label can be longer and more descriptive, but it should be no longer than a few words. For example, a Command's short label might be "Play," and its long label might be "Play Sound Clip."

  • Command type: The purpose of a command, selected from a defined set of constant types. The defined types are BACK, CANCEL, EXIT, HELP, ITEM, OK, SCREEN, and STOP. The implementation will use the command type for placing the command appropriately within the device's user interface. Commands with similar types may, for example, be found near each other in certain dedicated places in the user interface. Often, devices will have policy for the placement and presentation of certain operations. For example, a "backward navigation" command might be always placed on the right softkey on a particular device, but it might be placed on the left softkey on a different device. The Command class provides a fixed set of command types that provide MIDlets with the capability to tell the device implementation the intent of a Command. The application can use the BACK command type for commands that perform backward navigation. On the devices mentioned above, this type of information would be used to assign the command to the appropriate softkey.

  • Priority: A number that defines the relative importance between Commands of the same type on the same Displayable. A lower number indicates greater importance. A Command with a lower numeric priority value is more important than a Command of the same type but with a higher int priority value. If possible, a more important Command is presented before, or is more easily accessible than, a less important one.

Typically, the implementation first chooses the placement of a Command based on the type of Command and then places similar Commands based on a priority order. This could mean that the Command with the highest priority (lowest numeric priority value) is placed so that the user can trigger it directly and that Commands with a lower priority (higher numeric priority value) are placed on a menu. It is not an error to define Commands on the same screen with the same priorities and types. If this occurs, the implementation will choose the order in which the Commands are presented.

8.5.3 Command Types

Since the command type is the most important means for an application to adapt to the user interface style of a device, it is important that the applications correctly define the command types. Selecting a correct type for a Command makes applications more consistent with the native applications in a device. There are six command types that are used for more specific purposes:

  • BACK: Returns the user to the logically previous screen. The actual jump to the previous screen is done by the CommandListener provided by the application. The application is responsible, for example, for calling the setCurrent method in CommandListener to change the current displayable to the previous one. Note that the application defines the actual action, since the previous screen may not always be the logically correct place to jump to.

  • OK and CANCEL: Standard positive and negative answers to a dialog implemented by the current screen. With the OK command type, the application hints to the implementation that the user wants to use the command to confirm the data that has been entered in the current screen and to proceed to the next logical screen. With the CANCEL command type, the application hints to the implementation that the user wants to dismiss the current screen without taking any action on the data that has been entered in the current screen, and that the user (usually) wants to return to the prior screen. OK and CANCEL types should be used together if both positive and negative responses are available in a dialog. In many cases CANCEL is interchangeable with BACK, but BACK should be used for navigation only.

  • HELP: Activates online help. The help information should be presented using the Form class.

  • EXIT: Used for exiting the application. All applications should provide an exit function, and thus should have at least one EXIT type command.

  • STOP: Stops some currently running process, operation, or other action. With this command type, the application hints to the implementation that the user will use this command to stop any currently running process visible to the user on the current screen. Examples of running processes might include downloading or sending of data. Use of the STOP command does not necessarily imply a switch to another screen. STOP must not be used when Command is used to close the application; in this case the EXIT type must be used.

If none of the above command types describe the intent of the Command, then one of the two more generic command types must be used:

  • ITEM: With this command type the application can hint to the implementation that the command is specific to the items of the Screen or the elements of a Choice. Normally this means that command relates to the focused item or element. For example, an e-mail application might present the list of mail headers using a List screen. "Delete" or "Read" labeled commands in the List have ITEM type. Delete or Read commands only affect the highlighted List element, not all the elements in the List. The commands either delete the mail or open the mail in reader view.

  • SCREEN: This command type is used for commands that generally relate to or affect all of the items of a Screen or elements of a List. Examples could be "Delete all," "Load," or "Save." The SCREEN type should be used also if no other type is relevant for the intent of a Command. A SCREEN command generally applies to the entire screen contents or to navigation among screens. This is in contrast with the ITEM type, which applies to the currently activated or focused item or element contained within the screen.

class CommandExample extends Canvas implements CommandListener {
    Command save = new Command("Save", Command.SCREEN, 1);
    Command soundOff = new Command("Sound off", Command.SCREEN, 2);
    Command soundOn = new Command("Sound on", Command.SCREEN, 2);
    Command exit = new Command("Exit", Command.EXIT, 3);
    MIDlet midlet;

    public CommandExample(MIDlet owner) {
        midlet = owner;
        setCommandListener(this);
        addCommand(save);
        addCommand(soundOff);
        addCommand(exit);
    }

    public void setSound(boolean sound) {
        // ... implementation-dependent ...
    }

    public void paint(Graphics g) {
        // ... implementation-dependent ...
    }

    public void commandAction(Command cmd, Displayable d) {
        // (see code in next section)
    }
}

8.5.4 Command Listeners

The application-level handling of Commands is based on a listener model. Each Displayable object has a single listener. When the user invokes a Command on a Displayable, its listener is called. Listeners are registered using the method Displayable.setCommandListener. To define itself as a listener, an object must implement the interface CommandListener, which has following method:

void commandAction(Command c, Displayable d)

The application receives these command events if the Screen or Canvas has attached Commands and if there is a registered listener. Only a unicast version of the listener model is adopted, so the Screen or Canvas can have only one listener at a time. Here is a sample CommandListener interface method implementation for the CommandExample class defined above.

public void commandAction(Command cmd, Displayable d) {
    if (cmd == save) {
        // Save game state and show confirmation dialog
        Alert alert = new Alert(null, "Saved",
                                null, AlertType.CONFIRMATION);
        Display.getDisplay(midlet).setCurrent(alert);
    } else if (cmd == soundOff) {
        removeCommand(soundOff);
        addCommand(soundOn);
        setSound(false);
        Alert alert = new Alert(null, "Sound off",
                                null, AlertType.CONFIRMATION);
        Display.getDisplay(midlet).setCurrent(alert);
    } else if (cmd == soundOn) {
        removeCommand(soundOn);
        addCommand(soundOff);
        setSound(true);
        Alert alert = new Alert(null, "Sound on",
                                null, AlertType.CONFIRMATION);
        Display.getDisplay(midlet).setCurrent(alert);
    } else if (cmd == exit) {
        // Exit the application
        midlet.notifyDestroyed();
    }
}


8.6 Advanced Topics

The following sections present more advanced topics related to the MIDP user interface libraries.

8.6.1 System Screens

Typically, the current screen of the foreground MIDlet is visible on the display. However, under certain circumstances, the system may create a screen that temporarily obscures the current screen of the application. These screens are referred to as system screens. This may occur if the system needs to show a menu or if the system requires the user to edit text on a separate screen instead of a TextField inside a Form. Even though the system screen obscures the application's screen, from the viewpoint of the application the notion of the current screen does not change. In particular, while a system screen is visible, a call to the method getCurrent will still return the application's current screen, not the system screen. The value returned by the method isShown is false while the current Displayable is obscured by a system screen.

If the system screen obscures a Canvas, the hideNotify method of the Canvas is called. When the system screen is removed, restoring the Canvas, its showNotify method and then its paint method are called. If the system screen was used by the user to issue a command, the commandAction method is invoked automatically after the showNotify method is called.

8.6.2 Adaptation to Device-Specific User Interface Style

The lcdui API contains several methods to query the user interface properties of the target device.

The Display class provides methods to query the color capability of the client device. The methods isColor, numColors, and numAlphaLevels provide information about whether the device has a color or monochrome display, the number of colors (or gray levels), and the number of supported alpha-channel levels in off-screen images, respectively.

The Display class also has methods to retrieve the prevailing foreground and background colors of the high-level user interface. These methods are useful for creating CustomItem objects that match the user interface of other items and for creating user interfaces within Canvas that match the user interface of the rest of the system. Implementations are not limited to using foreground and background colors in their user interfaces (for example, they might use highlight and shadow colors for a beveling effect), but the color values returned are those that match reasonably well with the color scheme of a device. An application implementing a custom item should use the background color to clear its region and then paint text and geometric graphics (lines, arcs, rectangles) in the foreground color.

The system colors can be queried with a method:

public int getColor(int colorSpecifier)

The color specifiers are:

  • COLOR_BACKGROUND

  • COLOR_FOREGROUND

  • COLOR_BORDER

  • COLOR_HIGHLIGHTED_BORDER

  • COLOR_HIGHLIGHTED_BACKGROUND, and

  • COLOR_HIGHLIGHTED_FOREGROUND.

The getBorderStyle method is used to query which border style is used in the device for highlighted and non highlighted components. Similarly, using class Font, some of the device fonts, FONT_INPUT_TEXT and FONT_STATIC_TEXT, can be queried using the method:

public static Font getFont(int fontSpecifier)

The method returns a Font object that matches fonts used in text editors such as TextField, and for static text presented in Items.

Class Display also provides the methods getBestImageWidth and getBestImageHeight for querying the preferred sizes of images used in high-level components. The Displayable class provides the methods getWidth and getHeight to check the screen size provided for the application.

The methods for querying screen or component sizes and low-level input capabilities are provided in the classes Canvas and CustomItem. For the applicable methods of class CustomItem, refer to Section 10.8.1, "Interaction Modes." For the applicable methods of class Canvas, see Section 11.2.3, "Pointer Events."

8.6.3 Device-Provided Operations

In many high-level user interface classes such as Screens there are some additional operations that are visible only to the end user and not to the applications. This means that the user interface may present commands for which no listeners or event mechanisms are available in the lcdui API. When the user activates such device-provided operations, no application listeners are called.

The set of available operations depends on the user interface design of the specific device. For example, in the TextBox class, an operation that allows the user to change the mode for text input between alphabetic and numeric is needed in devices that have only an ITU-T keypad. Many devices with an ITU-T keypad have more complex predictive input systems, and these require additional operations in TextBox. Some of the operations are presented in the user interface in the same way as application-defined commands. End users need not understand which of the operations are provided by the application and which are provided by the system. Not all operations are available in every implementation. For example, a system that has a word-lookup-based text input scheme will generally provide additional operations within the TextBox class. A system that lacks such an input scheme will also lack the corresponding operations.

Some operations are available on all devices, but the way the operation is implemented may differ greatly from device to device. Examples of such operations are: the mechanism that is used to navigate between List elements and Form items, the selection of List elements, moving the insertion point within a text editor, and so forth. Some devices do not allow the direct editing of the value of an Item, but instead require the user to switch to an off-screen editor. In such devices, there must be a dedicated selection operation that can be used to invoke the off-screen editor. The selection of List elements could be, for example, implemented with a dedicated "Go" or "Select" key. Some devices have no dedicated selection key and must select elements using some other means.

On devices where the selection is performed using a dedicated select key, this key will often not have a label displayed for it. It is appropriate for the implementation to use this key in situations where its meaning is obvious. For example, if the user is presented with a set of mutually exclusive options, the selection key will obviously select one of those options. However, in a device that does not have a dedicated select key, it is likely that the selection operation will be implemented using a softkey that requires a label. The ability to set the select command for a List of type IMPLICIT and the ability to set the default command for an Item are provided so that the application can set the label for this operation and can therefore receive a notification when this operation occurs.

8.6.4 A Note on Concurrency

The MIDP user interface API has been designed to be thread-safe. There are methods that may be called from callbacks, for example, the methods of a CommandListener, ItemCommandListener, ItemStateListener, TimerTask, or a Thread created by the application. The MIDP system implementation handles its own locking and synchronization to make this possible.

The application is responsible for the synchronization of its own objects and data structures. The MIDP user interface API purposefully serializes callbacks to listeners of high-level API and calls to the event notifications methods of class Canvas, so in most cases the application does not need to perform locking.


8.7 New for MIDP 2.0

We have marked a number of topics in this chapter as New! with an icon in the book margin. The user interface capabilities of the high-level user interface have been dramatically improved to allow increased control by the application developer over the layout and visual elements.

Class Display has been improved to allow:

  • the querying of the colors used by the device for normal and highlighted colors for foreground, background, and borders (see the getColor method),

  • the activation of the backlight and vibrator of the device as added effects to gain the attention of the user (see the vibrate and flashBacklight methods),

  • the querying of the best width and height for Images used in Lists, Choice elements, and Alerts (see the getBestImageWidth and getBestImageHeight methods),

  • the querying of the number of alpha levels supported (see the numAlphaLevels method), and

  • the querying of the border style used for highlighted and normal elements (see the getBorderStyle method).

Class Displayable has been extended to allow:

  • a title and Ticker to be set for any Displayable including Canvas (see the setTitle and setTicker methods), and

  • the querying of the width and height of any Displayable; previously this was only possible for Canvas objects (see the getWidth and getHeight methods).

Abstract Commands have been enhanced to provide:

  • the ability to create Commands with both a short label and long label; which one is used depends on the context and the available display area (see the constructor and getLonglabel methods).


Chapter 9. MIDP High-Level User Interface – Screen

Each subclass of class Screen is a complete functional user interface element. The software in a given MIDP device implements each kind of Screen using the native look and feel of the device. The device software takes care of all events that occur as the user navigates in a Screen. When a user action causes a Command invocation event, the event is passed to the application, which brings about a transition to a different Screen. Each Screen can have a title, multiple Commands, and a Ticker. It is up to the device software to include these elements in the visual presentation of the Screen. The four kinds of Screens (List, TextBox, Alert, and Form) are described in this chapter.


9.1 List

The List class is a Screen that displays a list of choice items. The choice items are called elements. Each element has an associated string and may have an icon (an Image). There are three types of Lists: implicit, exclusive, and multiple choice. The type of the List is selected when the List is constructed and cannot be changed during the lifetime of the List object. The look and feel of Lists varies from one type of List to another, as illustrated in the examples below. Also, note that different MIDP implementations may render the Lists differently.

When a List is being displayed, the user can interact with it, for instance, by traversing from element to element. The traversal may cause the List to be scrolled. These traversing and scrolling operations are handled by the system and do not generate any events that are visible to the MIDP application. The system notifies the application only when a Command is fired. The notification to the application is carried out via the CommandListener of the Screen. This means that the application operations associated with list elements are added to the List as ITEM or SCREEN type commands, depending upon whether the operation affects only the selected element or the entire list.

In the List class there is also a notion of the select operation, which is central to the user's interaction with the List. The select operation is implemented differently from device to device. On devices that have a dedicated hardware key for selection operations, such as a "Select" or "Go" key, the select operation is invoked with that key. Devices that do not have a dedicated key must provide other means to perform the select operation; for example, using a labeled softkey. The behavior of the select operation within the three different types of lists is described in the following sections: Section 9.1.1, "Implicit List," Section 9.1.2, "Exclusive Choice List," and Section 9.1.3, "Multiple Choice List."

Methods on List objects include insert, append and delete, and methods to get the String or the Image from any element. Elements can be added and removed from the List at any time. The selected elements in the List can be retrieved or changed. However, changing the List while the user is viewing it or trying to select an item is not recommended since it might cause confusion.

The majority of the behavior for managing a List is common with class ChoiceGroup; the common API is defined in the interface class Choice. Elements in the List are manipulated with the methods append, delete, getImage, getString, insert, and set. Item selection is handled with methods getSelectedIndex, setSelectedIndex, getSelectedFlags, setSelectedFlags, and isSelected.

Here is an example of List creation:

List list = new List("Fruits",
                     Choice.IMPLICIT);
list.append("Apple", null);
list.append("Pear", null);
list.append("Orange", null);
list.append("Banana", null);
list.append("Pineapple", null);
list.append("Mandarin", null);
list.setCommandListener(this);
list.addCommand(backCommand);

9.1.1 Implicit List

An implicit List is used as a normal selection list. The List is presented as a menu from which the user can choose one of the elements. As with other List types, there can be one or more available operations provided as Commands. The operations that operate in the context of the selected element are provided as ITEM type Commands. In other words, List operations that affect or are related to the focused or highlighted element should have the type ITEM. The correct type allows MIDP devices to place the context-sensitive operations in the correct place in the user interface.

The implicit List automatically selects the currently focused element when any Command is initiated. To be notified of the selection, the List must have a CommandListener set. The application can query the selection state of a List from CommandListener using the methods getSelectedIndex or isSelected.

The implicit List also has the concept of a select command. A select command is a command that the user can activate with the select operation of the device. This user action delivers the select command to the CommandListener of the List. An application can set a select command with the method setSelectCommand. Initially, when a List is constructed, the select command is set to be the built-in List.SELECT_COMMAND. As a general rule, applications should provide their own select command to replace the built-in SELECT_COMMAND. This allows applications to provide a meaningful label instead of relying on the one provided by the system for SELECT_COMMAND.

The select command can also be removed completely by passing null to the setSelectCommand method. There is a special usage scenario for this. There can be multiple ITEM commands on a List, but there can be only one select command. In some cases, none of the ITEM commands can be considered suitable for being a select command.

If there is more than one ITEM command on a List, the select command can be considered as a default operation for the List. The following code sample illustrates how this can be accomplished. The code creates a list that presents the message headers of an e-mail messaging application. Two of the commands, openCommand and removeCommand, are related to the List elements, so they have type ITEM. The openCommand is considered to be a default operation, invoked when a select operation in the List is activated by the user.

The following code initializes the List:

// Construct a list of message headers
List list = new List("Messages", Choice.IMPLICIT,
                     messageHeaders, messageStateIcons);

// The command handler is implemented in the same class
list.setCommandListener(this);

// Command for "opening" the selected message
Command openCommand = new Command("Open", Command.ITEM, 1);

// Command for "removing" the selected message
Command removeCommand = new Command("Remove", Command.ITEM, 2);

// Command for going "back"
Command backCommand = new Command("Back", Command.BACK, 3);

list.addCommand(openCommand);
list.addCommand(removeCommand);
list.addCommand(backCommand);
list.setSelectCommand(openCommand); // openCommand is the default

The following code defines the command handler of the List:

public void commandAction(Command cmd, Displayable d) {
    int selectedIndex = ((List) d).getSelectedIndex();
    if (cmd == openCommand) {
        // Handle "open" command based on selectedIndex
    } else if (cmd == removeCommand) {
        // Handle "remove" command based on selectedIndex
    } else if (cmd == backCommand) {
        // Handle backward navigation
    }
}

9.1.2 Exclusive Choice List

An Exclusive List allows the user to select only a single element. This type of a List is commonly rendered to the screen as a group of radio buttons. When the user selects an element, any previously selected element is automatically deselected. Selecting an element does not notify the application. Notification to the List's CommandListener occurs when a Command on the List is chosen. When the listener is invoked, it can determine which element is selected with the List.getSelected method. An exclusive List must have Commands added to it, or the user will not be able to trigger any action and will be stuck on the screen. In the example below, the user is able to pick one element and then can select either the OK or BACK command.

List list =
  new List("Border Style", Choice.EXCLUSIVE);
list.append("None", null);
list.append("Plain", null);
list.append("Fancy", null);
list.addCommand(backCommand);
list.addCommand(okCommand);
...

public void commandAction(Command cmd, Displayable d) {
    List list = (List) d;
    if (cmd == okCommand) {
        int i = list.getSelectedIndex();
        // Use the index of the selected list element...
    } else if (cmd == backCommand) {
        // Handle the back command
    }
}

9.1.3 Multiple Choice List

A Multiple Choice List allows the user to select zero or more elements. Each element can be selected or deselected individually. Typically, this kind of List is presented on the screen as a set of check boxes. Each element has an indicator displaying whether or not the element it is currently selected, and the user can toggle individual elements on or off. Toggling the selection of an element does not notify the application. Notification to the List's CommandListener occurs when a Command on the List is chosen. When the listener is invoked, it can determine which element(s) are selected with the List.getSelectedFlags or List.isSelected method. A multiple choice List must have Commands added to it, or the user will not be able to trigger any action and will be stuck on the screen.

In this example, the user can individually select and deselect the choices "Red", "Green", and "Blue." When satisfied with the choices, the user can select either the OK or BACK command to exit the screen.

List list = new List("Colors to mix",
                     Choice.MULTIPLE);
list.append("Red", null);
list.append("Green", null);
list.append("Blue", null);
list.addCommand(backCommand);
list.addCommand(okCommand);
...

public void commandAction(Command cmd,
                          Displayable d) {
    if (cmd == okCommand) {
        List list = (List) d;
        for (int i = 0; i < list.size(); i++) {
            boolean selected = list.isSelected(i);
            // If selected, take action...
        }
    }
}

9.1.4 Long List Elements

In MIDP 2.0, an application can set a preference indicating what to do with longer element text that does not fit in a single line in a List. The setFitPolicy(int fitPolicy) method controls this preference, but a device may decide to ignore the application preference. The valid settings of the element fit policy are TEXT_WRAP_DEFAULT, TEXT_WRAP_ON, and TEXT_WRAP_OFF. The initial value of the element fit policy is TEXT_WRAP_DEFAULT, which indicates that the normal device-specific wrapping policy is used.

If the TEXT_WRAP_ON request is honored, the text element contents are wrapped to multiple lines, if necessary, up to the available content space. Conversely, TEXT_WRAP_OFF causes the text element contents to be limited to a single line. Line ending is forced, usually by cropping, if there is too much text to fit in the line.

9.1.5 List Element Fonts

Each List element has a Font that may be used in drawing the text part of the element. An element font that is set by an application is just a hint from the application; some devices might not use it for rendering the text. The same Font class used in the low-level Graphics API is used in element fonts. An application can set the Font of an element with the method setFont(int elementNum, Font font). By default, all elements of a List have the same font. The default Font is determined by the device and is the font most commonly used in selection lists. If an application changes the element font, it can later restore the default font with the call setFont(elementNum, null).

There are two general usage scenarios for setting a font for a List that differs from the default. First, the element fonts with differing styles (such as plain, bold, or italic) might be used to highlight some implicit difference in elements. For example, in an e-mail client application, "unread" items might be presented using a bold font, and "read" items with plain font. Because the default font can itself be bold or plain, the application should, as a general rule, set all the element fonts, or else it should query the default font and create a variant font based on the properties of the default font. This also helps ensure that the font sizes of different elements remain consistent:

// Get the default font
Font defaultFont = list.getFont(0);
int defaultFontFace = defaultFont.getFace();
int defaultFontSize = defaultFont.getSize();

// Define a style that differs from the default font
int readFontStyle;
if (defaultFont.isBold()) {
    // If default is itself bold, use bold and italic
    readFontStyle = Font.STYLE_BOLD | Font.STYLE_ITALIC;
} else {
    // Otherwise use simply bold
    readFontStyle = Font.STYLE_BOLD;
}

// Get a new font with only the style differing from default font
Font readElementFont = Font.getFont(defaultFontFace, readFontStyle,
                                   defaultFontSize);
// Set the readElementFont for "unread" elements
for (int i = 0 ; i < list.size() ; i++) {
    // readState array contains boolean true if item is read
    if (!readState[i]) {
        list.setFont(i, readElementFont);
    }
}

The second general use case is that the setFont method can be passed a font that differs in size from the default font. If this is done, the application should change the font of all elements to have the same size. If the List element font sizes differ from element to element, this could result in awkward-looking user interfaces. Some devices might limit the element sizes of Lists, so it might not be possible for the application to completely control the font sizes.

For more a detailed description about Font properties and their proper values refer to Section 11.3.6, "Fonts."


9.2 TextBox

The TextBox class is a Screen that allows the user to enter and edit text. The input devices and input methods[1] for the text entry differ dramatically from device to device. Many devices have only a numeric keypad, which allows text entry by repetitive tapping of the number keys. Also, there can be separate user-changeable input modes: for example, separate modes for entering text and numbers.

[1] Input methods are software components that interpret user operations on input devices, such as typing keys, speaking, or writing using a pen device to generate text input.

Many numeric keypad devices have a more advanced input method called predictive input.[2] If there are several alternate input methods available, the user can often select which input mode to use in the editor. Some MIDP devices may have full-character keyboards, and devices with touch screen often have on-screen virtual keyboards. The input methods differ also from language to language. For example, in Chinese devices there are several different input modes. These different methods are not directly visible to applications, but developers should bear in mind that in many devices the input of long character strings might be cumbersome or rather slow. In MIDP 2.0, an application now has more concrete control on the input modes used, as described later in this subsection.

[2] Predictive input enables text entry with a numeric keypad using only one key press per letter in most common cases.

An application defines the maximum size of the TextBox, which is the maximum number of characters that the editor can contain. The application also sets the input constraints for the editor. These parameters are described in detail in the next section (Section 9.2.1, "Input Constraints.") The characters in the TextBox can be modified and retrieved by the application either as a String or a sequence of characters.

The capabilities of the device determine a limit on the maximum size. The maximum size available may be smaller than the application had requested. The maximum size value is returned from both the setMaxSize and getMaxSize methods. The TextBox constructor and methods that change the text contents throw an IllegalArgumentException if the contents exceed maximum size. This means that when the application needs to use some initial value in the TextBox, it should compare the value returned from getMaxSize to the size of the String that it intends to use in the TextBox.

A TextBox must have Commands added to it. Otherwise, the user will not be able to trigger any action and will be stuck in the TextBox.

This sample code illustrates the creation of a TextBox with an initialized editable phone number and two commands.

TextBox text = new TextBox("Phone",
                   "18005551212", 50,
                   TextField.PHONENUMBER);
text.addCommand(backCommand);
text.addCommand(okCommand);

9.2.1 Input Constraints

The application can set the input constraint individually for each TextBox. The constraints are defined in the TextField class (see Section 10.4, "TextField") but are also available in TextBoxes. The available input constraint are ANY, NUMERIC, DECIMAL, PHONENUMBER, URL, and EMAILADDR. The device can use the input constraints to make it easier for the user to input allowed characters or can use them to format the field value for display. This means that the available input modes are likely to be affected by the input constraints.

The NUMERIC and DECIMAL constraints force the contents to numerical values. For example, if the device has a specific input mode for numbers, then the editor is fixed to that mode. NUMERIC is used for entering integer numbers that are, however, returned to applications as strings. DECIMAL is a new constraint in MIDP Specification version 2.0. It is used for entering numerical values that might contain decimal fractions. PHONENUMBER is used for entering phone numbers. Other types are used for alphanumerical entry without any character restrictions other than those imposed by the device itself.

The ANY constraint is the most generic alphanumeric type for creating a generic text editor for entering free-form text. The input constraints EMAILADDR and URL allow the input of the same characters as ANY but give hints about the contents of the editor. These constraints do not automatically validate the format or syntax of the input but may be used by the device implementation to choose a better input mode: for example, automatic capitalization and predictive input may be turned off by default in EMAILADDR and URL editors.

The PHONENUMBER type constrains the entered characters to those available in phone numbers. The set of special characters in phone numbers differs from device to device and is likely based on the network standard for which the device is intended. In a PHONENUMBER TextBox, the numeric keypad can be automatically enabled for direct input of numbers, and the output can be formatted as a phone number using device-specific or network-specific formatting rules.

The text editor may also include device-specific operations. For instance, a PHONENUMBER TextBox may have an operation that allows the user to copy a phone number to be input to the editor from the device-specific phone book application. The device may also enable the "TALK" button on the phone to dial the number. This provides applications with a simple way to present a phone number to the user and to allow the user to dial that number.

There are additional modifiers for the input constraints. The input constraint modifiers are:

  • PASSWORD: Used when confidential data needs to be entered. The device typically masks the data with a "*" character.

  • UNEDITABLE: When this modifier is active, the user cannot edit the contents.

  • SENSITIVE: Used to indicate that the text entered is sensitive and must never be stored in any auto-completion or predictive input dictionaries that the devices might normally use.

  • NON_PREDICTIVE: Indicates that device should not use predictive input even if such an input method is available on the device. The mode can be used if the text to be entered is something that most likely cannot be entered with predictive input methods. The user interaction thus becomes more seamless, since the user does not need to turn predictive input off manually. On a device that does not have predictive input, this modifier is simply ignored.

  • INITIAL_CAPS_WORD: Is a hint to the implementation that during text editing, the initial letter of each word should be capitalized. The flag is useful, for example, for entering names in an address book application.

  • INITIAL_CAPS_SENTENCE: This flag is a hint to the implementation that during text editing, the initial letter of each sentence should be capitalized.

The modifiers are used by combining the set of modifiers with constraints using the bitwise OR operator. For example, the constraint "NUMERIC | PASSWORD" creates an editor that allows the input of numeric passwords only.

9.2.2 Input Modes

The application can request that the implementation use a particular input mode when the user initiates the editing of a TextBox. As described earlier, devices often have multiple input modes for text entry. These input modes allow easy text entry for certain types of text, such as numeric or lowercase alphabets, or specific modes for different languages. If the requested mode is not supported by the device, normal text entry mode is used.

The MIDP Specification does not try to specify all the possible input modes found in devices. Rather, the specification is based on the idea that the applications themselves define for which characters input should be made as convenient as possible. The input modes are identified by strings. The MIDP Specification defines standard rules for the input mode strings and specifies a set of concrete strings that may be used by devices. The specification also allows the set to be extended by the device implementations. The initial input mode is set with the method:

public void setInitialInputMode(String characterSubset)

This method allows the application to specify the input mode best suited for the editor. If a device supports the input mode, the TextBox is initially set to that mode, but the user may select another one from the device-specific menus.

Many of the input mode strings are based on Unicode character blocks. For example, the UCB_BASIC_LATIN input mode allows the easy input of Latin characters, and UCB_HIRAGANA is the input mode that is specific to the Japanese language Hiragana script characters. There are also input modes that define subsets of the Unicode blocks. For example, the following Latin-specific modes are available: MIDP_UPPERCASE_LATIN for uppercase mode, MIDP_LOWERCASE_LATIN for lowercase input mode, and IS_LATIN_DIGITS for Latin number entry.

The input mode settings have a lower priority than the input constraints. If the input constraint and input mode are in conflict, then the input mode is ignored. For example, if the constraint is set to NUMERIC and mode to MIDP_UPPERCASE_LATIN, the input mode is ignored and numeric input is activated.

Often an initial input mode is used simply with the input constraint ANY. In many cases, however, the input modes can be combined with constraints other than ANY. For example, the NUMERIC constraint together with UCB_ARABIC input mode initially sets the editor to number entry with Arabic-Indic digit input mode (if supported by the device.)


9.3 Alert

Alerts are Screens that can be used to inform the user about errors and other exceptional conditions. Alerts can also be used as short informational notes and reminders. For the presentation of longer information, other Screen classes such as Form should be used.

An Alert shows a message and an optional Image to the user. An Alert is either presented for a certain period of time, or it can be modal with a special user operation to dismiss (close) the Alert.

The time the Alert is presented can be controlled with the setTimeout method. If the timeout is not set by application, the Alert timeout is the default timeout determined by the device. The default value can be inspected using the getDefaultTimeout method.

The Alert is set to be modal if the application sets the alert time to be infinite with the method call setTimeout(Alert.FOREVER). A timed Alert is forced to be modal if the device cannot present the Alert contents without scrolling. In modal Alerts the device provides a feature that allows the user to dismiss the Alert, whereupon the next screen is displayed.

Timed Alerts can be used when the user does not need to be aware of the information presented and can safely ignore the Alert. Alerts without a timeout should be used when the user must be made aware of the information or condition.

When an Alert is dismissed either explicitly by the user or after a timeout, the current displayable is automatically changed to the next screen. When an Alert is displayed, the application can choose which Displayable is to be displayed after the Alert is complete. This is done by using a specialized setCurrent method of class Display:

public void setCurrent(Alert alert, Displayable nextDisplayable)

If the normal setCurrent(Displayable nextDisplayable) method is used, the display reverts to the current screen after an Alert exits.

The AlertType of an Alert can be set to indicate the nature of the information provided in the Alert. There are five AlertTypes; ALARM, CONFIRMATION, ERROR, INFO, and WARNING. ERROR and WARNING are used for error messages. WARNING should be used when the user has the possibility to prevent the error and ERROR when some non preventable error has already occurred. CONFIRMATION and INFO are used for more positive informational notes. CONFIRMATION is used when the user should confirm that some action has taken place. For example, after the user has selected some element from a settings List, a CONFIRMATION may be presented to the user to indicate that the setting has been changed. The INFO type is used for more generic positive informational notes. The ALARM type should be used when some notification is presented that interrupts the normal interaction in some other way. For example, a calendar application may use the ALARM type for notifying the user that a timed calendar event has been triggered.

The AlertType settings affect the presentation of the Alert. For example, if an application does not provide any image for the Alert, then the device implementation may present some default system icon based on the AlertType. For example, an exclamation icon might be used in an ERROR Alert. AlertTypes can also have system sounds associated with them so that the device can audibly alert the user. The presence and selection of sounds is device-dependent. The sound associated with the AlertType can be played anytime by calling the method AlertType.playSound.

An example of an Alert is shown below:

Alert alert = new Alert("Cinema",
               "Two tickets purchased",
               null,
               AlertType.CONFIRMATION);
alert.setTimeout(4000);
display.setCurrent(alert);

9.3.1 Commands in Alert

Commands added to an Alert make it easy to create query dialogs with a set of predefined user responses such as "OK" and "Cancel." When Commands are added to an Alert, the built-in dismiss operation is removed. Similarly, when a CommandListener is set, the automatic advance behavior is deactivated, and the application must take care to call setCurrent when Alert should be removed from the display.

An Alert that has two or more application-defined Commands is always modal. If there is only one Command in a timed Alert, then the Command is activated automatically when the timeout occurs.

The semantics of an AlertType are slightly different when an Alert is a dialog with multiple answers (Commands.) The alert types generally indicate some forthcoming situation rather than something that has already been happened. For example, ERROR or WARNING can indicate that something erroneous or a harmful situation may result when choosing some of the Commands in Alert; for example, when user data may be lost. CONFIRMATION type should be used in dialogs that indicate less destructive actions. ALARM type is used similarly, but mainly to notify the user of an event that has occurred. For example, the ALARM type might be used to "Snooze" or "Dismiss" an alarm clock application.

An example:

Alert alert = new Alert(null, null, null,
               AlertType.CONFIRMATION);
alert.addCommand(okCommand);
alert.addCommand(backCommand);
alert.setCommandListener(this);
String prompt = "Delete address?\n\n";
String detail = "john.doe@foo.bar";
alert.setString(prompt + detail);
display.setCurrent(alert);

9.3.2 Activity Indicator

An Alert may contain a non-interactive Gauge object that is used as an activity or progress indicator. This can be used for creating simple wait or progress dialogs when there is some background process occurring and the user has to wait for the operation to be completed. For example, an activity indicator might be used when an application is downloading a large amount of data from the network. The Gauge class is described more thoroughly in Section 10.7, "Gauge." There are, however, certain constraints for the Gauge object when it is used as activity indicator in an Alert. For example, the Gauge must be set to non-interactive mode, and there must not be any label or any item Commands in it. The constraints are documented in more detail in the MIDP Specification version 2.0.

Alert alert = new Alert("Cinema",
                        "Sending message",
                        null, null);
alert.setTimeout(4000);
Gauge indicator = new Gauge(null, false,
                    Gauge.INDEFINITE,
                    Gauge.CONTINUOUS_RUNNING);
alert.setIndicator(indicator);
display.setCurrent(alert);


9.4 Form

A Form is a Screen that may contain a combination of Items, including StringItems, ImageItems, editable TextFields, editable DateFields, Gauges, and ChoiceGroups. Any of the subclasses of Item defined by the MIDP Specification may be contained within a Form. The device handles layout, traversal, and possible scrolling automatically. The entire contents of the Form scroll up and down together. Horizontal scrolling is not generally available. This means that the MIDP Specification does not forbid a device to implement this, but it is not endorsed. When a device allows only vertical scrolling, the layout and traversal model is easier and matches the limited set of controls available on a typical mobile information device. Applications must be written with this limitation in mind. For example, a CustomItem subclass needs to designed so that it works in varying screen widths without any horizontal scrolling support.

The methods for modifying the sequence of Items stored in a Form include insert, append, delete, get, set, and size. MIDP 2.0 devices also have a deleteAll method. Items within a Form are referenced by indices. The first Item in a Form has an index of zero and the last has the index size()-1.

The code sample below creates an empty Form container to be used as an options selection screen. This simple example has a title for the Form and Commands for accepting and canceling the Form contents. This kind of empty Form should be avoided in real applications.

Note that we will return back to this example in Chapter 10 when we illustrate the use of the Form class in more detail. The code below serves as a starting point for an "Options" selection form of a photo album application. The example will continue in Section 10.1, "Item," where we show how to add different Item class instances to this Form.

Form form = new Form("Options");
form.addCommand(backCommand);
form.addCommand(okCommand);
form.setCommandListener(this);
// Items are added later (see below)
display.setCurrent(form);

Refer to Chapter 10, "MIDP High-Level User Interface – Form" for more information on using the Form class.


9.5 New for MIDP 2.0

We have marked a number of topics in this chapter as New! with an icon in the book margin. Here is a summary of the most important new high-level user interface features of MIDP 2.0 described in this chapter.

Each of the Screen classes has been enhanced to provide more control over presentation and event handling.

The Font class has been extended to allow:

  • the querying of the default Font for static text and input text (see the getFont method).

The List class has been extended to allow:

  • the ability to get and set the Font of each element in the list (see the setFont and getFont methods),

  • the control of the wrapping or truncation of text within elements (see the setFitPolicy and getFitPolicy methods),

  • the ability to set the default command for selecting elements (see the setSelectCommand method),

  • the ability to delete all of the elements in the list with a single method (see the deleteAll method), and

  • the ability to set mutable Images as elements of a List (see the append, insert, and constructor methods).

The Alert class has been extended to allow:

  • the Images in an Alert to be mutable (see the setImage method),

  • a Gauge to be used as a progress indicator in the Alert (see the setIndicator and getIndicator methods),

  • one or more Commands to be added and to replace the default dismiss command (see the addCommand and removeCommand methods), and

  • setting a command listener to allow the application to handle Commands and to disable the built-in timer and command handling (see the setCommandListener method).


Chapter 10. MIDP High-Level User Interface – Form

A Form object is a Screen that presents a sequence of Items. Form objects are commonly used in MIDP applications to present data that consists of various different types such as text, images, editable date fields, text fields, and so on. This chapter describes the various Item classes and their features in detail, along with a description of class ItemStateListener that can be used to listen for changes in Item objects. In the end of this chapter, the rules for Form layout management are presented.


10.1 Item

Class Item is a superclass of all those components that can be attached to a Form. An Item can be contained only in a single Form at a time. The application must remove the item from the Form in which it is currently contained before inserting it into another Form.

All Item objects can have a label field, which is a String representing the title of the Item. If the label String is null, then no label is presented. The label is typically displayed near the Item when the Item is visible on the screen. If the screen is scrolling, the implementation tries to keep the label visible at the same time as the Item.

10.1.1 ItemStateListener

When the user changes an editable Item in a Form, the application can be notified of the change by implementing the ItemStateListener interface and setting the listener on the Form. The itemStateChanged method of the ItemStateListener set on the Form is called automatically when the value of an interactive Gauge, ChoiceGroup, DateField, or TextField changes. The listener is set for the Form using the setItemListener method. It is not expected that the listener is called after every event that causes a change. However, if the value has changed, the listener is called sometime before it is called for another Item, or before a Command is delivered to the ItemStateListener of the Form.

Continuing the example started in Section 9.4, "Form," the ItemStateListener would be set as follows:

form.setItemListener(this);

10.1.2 Item Commands

In MIDP 2.0, context-sensitive Commands can be added to Items. Commands added to an Item are made available to the user only when the focus is on that Item. As with Commands added to Displayables, the device implementation decides how the Commands are presented in the user interface. For example, the Commands might appear as a context-sensitive menu for the Item or as a normal menu when the Item is being manipulated by the user.

Context-sensitive Commands are used much like ordinary Commands in Displayables. The addCommand and removeCommand methods of the Item class control which Commands are associated with Items. There is a dedicated listener type called ItemCommandListener that is notified automatically when the user activates a Command of an Item. The listener of an Item is set with the setItemCommandListener method.

One of the Commands of an Item can also be chosen as the default Command using the method setDefaultCommand. A device may make this Command more easily accessible, for example, using the "Select" key of a device if such a key is available.

For an example on item command use, refer to the sample code in Section 10.2.1, "Appearance Modes."


10.2 StringItem

Read-only strings can be added to a Form either directly as Strings (Java String objects) or as StringItems. StringItem is a simple class that is used to wrap Strings so they can be treated consistently with the other Items. Strings are converted to StringItems automatically when they are appended to a Form. These kinds of StringItems have null labels. When an Item that was appended as a String is retrieved from a Form, it is returned as a StringItem.

Continuing the example started in Section 9.4, "Form," the following code illustrates how to add a new StringItem to the Form:

// Note: 'getImageName' is application-specific
String imageName = getImageName();
String si = new StringItem("Photo name:",
                           imageName);
form.append(si);

When a sequence of StringItems is displayed, the text is concatenated and wrapped to as many lines as needed. This has the effect that sequential StringItems are displayed as a paragraph of text. Any newline characters within StringItems are treated as row breaks (see Section 10.9.1, "Row Breaks"). Also, a label may cause a row break either before or after the label, or both. Generally, the label is used as a paragraph title.

Here is an example that illustrates the use of concatenated StringItems:

Form form = new Form("Concatenation");
... // Add Commands and CommandListener
form.append("First");
form.append("paragraph");
form.append("of text.");
Item si = new StringItem("Label", "Another");
form.append(si);
form.append("text paragraph");
form.append("here as an example.");
display.setCurrent(form);

10.2.1 Appearance Modes

The StringItem and ImageItem (see Section 10.3, "ImageItem") classes have an appearance mode attribute that controls the presentation of these items. There are three modes available: PLAIN, HYPERLINK, and BUTTON. By default, the mode is PLAIN in both items. Other modes can be used by creating a StringItem or ImageItem with a specialized constructor that receives an appearance mode argument.

Simply having an item with HYPERLINK or BUTTON appearance mode does not do anything. When either of these modes is used, the application must also add at least one Command to the item. Preferably, the Command is set as the default Command. In addition, an ItemCommandListener must be registered that actually will implement the action for the hyperlink or button.

Here's an example that illustrates the use of the HYPERLINK appearance mode:

Form form = new Form("Appearance");
Command backCommand = new Command("Back",
                         Command.BACK, 1);
form.addCommand(backCommand);
form.setCommandListener(this);

Item link = new StringItem(null, "link",
                         Item.HYPERLINK);
Command linkCommand = new Command("Go",
                         Command.ITEM, 1);
link.setDefaultCommand(linkCommand);
link.setItemCommandListener(this);

form.append("Follow this ");
form.append(link);
form.append(".");

Note that the linkCommand variable in the above code is set to the link StringItem whereas the backCommand variable is set to the entire Form. This means that the linkCommand operation is only accessible when the user is manipulating the link item. In other words, the presence of the linkCommand operation is context-sensitive.


10.3 ImageItem

Image objects can be added to a Form either directly as an Image or as an ImageItem. ImageItem is a simple class that wraps an Image. By default, the ImageItem is placed next to the previous StringItem or ImageItem. If an ImageItem is wider than the horizontal space available in the row, it is placed in a new row. Images wider than the Form width are clipped.

The ImageItem can be given a preferred layout policy with the setLayout method. The directive passed to this method defines whether the image is centered within the Form margins (LAYOUT_CENTER), left-justified (LAYOUT_LEFT), or right-justified (LAYOUT_RIGHT) and whether a forced line break is created before or after the image (LAYOUT_NEWLINE_BEFORE, LAYOUT_NEWLINE_AFTER). The layout is merely a hint for the device and might not be supported by the device. It also varies from device to device how the alignment directives are actually implemented. In some devices LAYOUT_LEFT might cause the ImageItem to float to the left margin, allowing nearby StringItems to wrap around the side of the image.

Continuing the example started in Section 9.4, "Form," the following code adds an ImageItem to the Form.

Image image = Image.createImage(
    "/images/PhotoAlbum.png");
ImageItem imageItem =
    new ImageItem(null, // (no label)
        image,
        ImageItem.LAYOUT_CENTER |
        ImageItem.LAYOUT_NEWLINE_AFTER |
        ImageItem.LAYOUT_NEWLINE_BEFORE,
        "(preview image)");
form.append(imageItem);

There is also a LAYOUT_2 directive that causes an ImageItem to follow the strictly specified MIDP 2.0 Form layout rules (discussed in Section 10.9, "Form Layout"). This means that the horizontal alignment directives LAYOUT_LEFT, LAYOUT_RIGHT, and LAYOUT_CENTER will behave the same way as in other Item classes. If LAYOUT_2 is not set, then the results are (for backwards compatibility reasons) implementation-specific since MIDP Specification version 1.0 did not define the behavior of the layout directives clearly for ImageItem.


10.4 TextField

A TextField is an editable text component that may be placed in a Form. The TextField API is exactly the same as that of TextBox. The only difference is the inherited functionality: TextField inherits from Item whereas TextBox inherits from Screen. Thus, as with TextBox, a TextField has a maximum size, input constraints and input mode (see Section 9.2, "TextBox"), a label, and a String value. The contents of a TextField can be either edited in-line in Form, or the Form may just present static text with a user operation to activate a separate editing view that allows the contents to be edited. The TextField contents within a Form are wrapped.

Devices dictate how many lines a TextField consumes. In some devices, the TextField height can grow dynamically based on the content.

An example:

TextField textField =
    new TextField("Photo caption:",
        "", 32, TextField.ANY);
form.append(textField);


10.5 DateField

A DateField is a component that may be placed in a Form in order to present date and time (calendar) information. The user is able to select a date or time value for the field. Devices have different kinds of editors for this. Some may allow the user to select a value with a graphical date or time selector, and in others the value is simply entered using the numeric keypad. The value for a DateField can be initially set or left unset. If the value is not set, the DateField.getDate method returns null. The user interface must visually indicate that the date and time are unknown.

Each instance of a DateField can be configured to accept either date or time information, or both. This input mode configuration is done by choosing the DATE, TIME, or DATE_TIME mode of this class. The DATE input mode configures the DateField to allow only date information and TIME to allow only time information (hours, minutes). The DATE_TIME mode allows both clock time and date values to be set.

An example:

DateField date =
    new DateField("Date", DateField.DATE);
date.setDate(new java.util.Date());
// Set date to "now"
form.append(date);


10.6 ChoiceGroup

A ChoiceGroup defines a group of selectable elements that can be placed within a Form. A ChoiceGroup is similar to a List (Section 9.1, "List"), but it supports only the exclusive and multiple choice modes.

Also available is a ChoiceGroup-specific POPUP mode. The selection behavior of a pop-up choice is identical to that of an exclusive choice. The pop-up choice differs from an exclusive choice in presentation and interaction. Whereas the EXCLUSIVE type of ChoiceGroup presents all the elements in line as a radio button list, the POPUP type shows only the currently selected element in line in the Form. The other elements are hidden until the user performs an action to show them. When the user performs this action, all elements become accessible. For example, a device may use a pop-up menu to display the elements.

Generally, the device is responsible for providing the graphical representation of these ChoiceGroup modes and must provide a visually different representation for different modes. For example, it might use radio buttons for the exclusive choice mode, check boxes for the multiple choice mode, and pop-up menus without any specific graphics for pop-up mode.

An example:

ChoiceGroup choice =
    new ChoiceGroup("Size:",
                    Choice.EXCLUSIVE);
choice.append("Small", null);
choice.append("Large", null);
form.append(choice);


10.7 Gauge

The Gauge class implements a graphical value display that may be placed in a Form. A Gauge displays a visual representation of a numeric value in the range between zero and the maximum value defined by the programmer. If the Gauge is set to be interactive, user actions can increase and decrease the value. Changes to the Gauge value are reported using an ItemStateListener. If the Gauge is set to be non-interactive, it represents a progress bar that can be used to provide feedback about the progress of long-running operations. The application can set and get the value of Gauge with the setValue(int) and getValue() methods. When Gauge is in non-interactive progress bar mode, the application must periodically update the value using the setValue method during the operation: the Gauge value should reach the maximum value just before the operation is finished.

Also available for a non-interactive Gauge is an indefinite range setting. This is used if there is no known endpoint to the activity. To define an indefinite Gauge, set the maximum value to the special INDEFINITE value. There are two kinds of indefinite Gauges available: CONTINUOUS_RUNNING and INCREMENTAL_UPDATING. These constants are used as Gauge range values. Continuous mode automatically animates the progress animation, whereas incremental mode requires that application call setValue(Gauge.INCREMENTAL_UPDATING) whenever there is an update in progress state.

For both of these modes there are separate idle modes that can be set with range values CONTINUOUS_IDLE and INCREMENTAL_IDLE, which indicate that no work is in progress. An application should use the idle modes with the correct pairs because the device progress graphics are typically designed so that, for example, CONTINUOUS_IDLE works well only in CONTINUOUS_RUNNING mode.

An example using interactive Gauge is:

Gauge gauge =
    new Gauge("Speed:", true, 10, 5);
form.append(gauge);

A non-interactive Gauge can also be placed in an Alert as an activity indicator. See Section 9.3.2, "Activity Indicator," for details.


10.8 CustomItem

The abstract class CustomItem allows applications to create new visual and interactive elements that can be used in Forms. To do this, a new subclass of CustomItem is created: it is responsible for creating the visual representation for the Item, including sizing and rendering. The subclass fully controls what is presented within item area. It defines the colors, fonts, and graphics that are used, including rendering of special highlight and focus states the item may have. Only the label of the item is rendered by the device, but the label is always rendered outside the CustomItem content area.

A CustomItem can trigger notifications to the ItemStateListener of a Form in which the CustomItem is contained. This is done by calling the notifyStateChanged method inherited from Item.

Like all Items, CustomItems have the concept of minimum and preferred sizes. These sizes pertain to the total area of the Item, which includes space for the content, label, borders, and so forth. (See Section 10.9.4, "Item Sizing," for a full discussion of the areas and sizes of Items.) A CustomItem does not itself fully control this area. There is, however, a smaller region within the CustomItem called the content area that the CustomItem subclass paints and from which it receives input events.

A CustomItem subclass overrides the methods getMinContentHeight, getMinContentWidth, getPrefContentHeight, and getPrefContentWidth to return the minimum and preferred sizes for the content area. The device is responsible for calculating the minimum and preferred sizes for the whole item. The device also defines the actual content area space made available for CustomItem. The size of this area is given in calls to the methods sizeChanged and paint:

protected void sizeChanged(int w, int h)
protected abstract void paint(Graphics g, int w, int h)

The actual size might be smaller than the requested minimum content size if the device cannot allocate the space requested. For example, if no horizontal scrolling is available in a device, there is a device-specific maximum size for item width, which in turn affects the maximum content size for CustomItems.

If the minimum or preferred content area size changes, an application must call the method invalidate, and the subsequent calls to the size methods must return the new content area sizes. The method invalidate tells a device that it needs to perform its layout computation, which calls the content size methods to get new values based on the new contents of the CustomItem.

10.8.1 Interaction Modes

Each CustomItem is responsible for adapting its behavior to the interaction methods available on a target device. A CustomItem subclass needs to call the method getInteractionModes to inspect the interaction modes that are supported by a particular device. This method returns a bit mask of the supported modes with bits set or unset for the following modes:

  • KEY_PRESS, KEY_RELEASE, and KEY_REPEAT for indicating the level of key press event support. Devices support either none of the key event modes, both press and release event modes, or all key event modes. It is not valid for a device to support key press events without supporting key release events.

  • POINTER_PRESS, POINTER_RELEASE, and POINTER_DRAG for indicating the level of pointer event support. Similar to key events, devices support either none of the pointer event modes, both press and release event modes, or all of the pointer event modes.

  • TRAVERSE_HORIZONTAL and TRAVERSE_VERTICAL for indicating support for internal traversal in a given direction, as discussed below.

10.8.2 Traversal

An implementation may support traversal inside a CustomItem; that is, the implementation may temporarily delegate the responsibility for traversal to the item itself. Even if there is only one traversal location inside the CustomItem, the item might want to support the internal traversal protocol so that it can perform specialized highlighting, animation, and so forth when the user has traversed into it.

The implementation indicates its support for traversal inside a CustomItem by setting one or both of the TRAVERSE_HORIZONTAL or TRAVERSE_VERTICAL bits in the value returned by getInteractionModes. If neither of these bits are set, the implementation is unwilling to let CustomItems traverse internally, or else the implementation does not support traversal at all. If the implementation does support traversal but has declined to permit traversal inside CustomItems, the implementation will supply its own highlighting outside the CustomItem's content area.

The CustomItem need not support internal traversal at all. It can do this by returning false to the initial call to the traverse method. (This is the default behavior if this method has not been overridden by the CustomItem.) If this occurs, the device must arrange for the user to be able to traverse onto and past this item. The device must also arrange for proper scrolling to take place, especially if the item size exceeds the height of the screen, regardless of whether internal traversal is occurring.

Refer to the documentation of the traverse method for a full specification of the required behavior and responsibilities of a CustomItem for performing internal traversal.


10.9 Form Layout

The Form class has a layout policy that is organized around rows. A Form grows vertically and scrolls vertically as necessary. The height of a Form varies depending upon the number of rows and the height of each row. The height of each row is determined by the items that are positioned on that row.

In MIDP 2.0, the Form layout algorithm considers each Item in turn, starting at Item zero and proceeding in order through each Item until the last Item in the Form has been processed. Items are laid out at the beginning of each row, proceeding across each row in the chosen layout direction, packing as many Items onto each row as will fit, unless a condition occurs that causes the packing of a row to be terminated early. A new row is then added, and Items are packed onto it as described above. Items are packed onto rows, and new rows are added below existing rows as necessary until all Items have been processed by the layout algorithm. This general principle of Form layout is illustrated in Figure 10.1.

Figure 10.1. General principle of Form layout

An application can influence the layout of the Items using the following layout directives:

  • LAYOUT_LEFT, LAYOUT_RIGHT, and LAYOUT_CENTER define the horizontal alignment of an items in a row.

  • LAYOUT_TOP, LAYOUT_BOTTOM, and LAYOUT_VCENTER define the vertical alignment of an item in a row.

  • LAYOUT_NEWLINE_BEFORE and LAYOUT_NEWLINE_AFTER force row breaks after and before an item.

  • LAYOUT_SHRINK, LAYOUT_VSHRINK, LAYOUT_EXPAND, and LAYOUT_VEXPAND affect the way an item is sized.

  • LAYOUT_2 indicates that new MIDP 2.0 layout rules are in effect for an item. LAYOUT_2 has no effect for StringItem, CustomItem, or Spacer.

These layout directives can be combined using the bitwise OR operator (|) to compose a layout directive value. The horizontal alignment directives are mutually exclusive. Similarly, multiple vertical alignment directives cannot be combined. All the other directives can be combined in any way with the other directives. Such a value is used as the parameter for the setLayout method and is the return value from the getLayout method.

The following example uses the setLayout method to set a combined layout directive value for a TextField. A LAYOUT_2 setting for TextField has the effect that other Items may also be placed in the same row. LAYOUT_SHRINK and LAYOUT_VSHRINK indicate that TextField should have the smallest possible size. LAYOUT_RIGHT and LAYOUT_TOP indicate that the TextField is aligned to the top or right side of the row.

TextField textField = new TextField(...);
textField.setLayout(Item.LAYOUT_2      |
                    Item.LAYOUT_SHRINK | Item.LAYOUT_VSHRINK |
                    Item.LAYOUT_RIGHT  | Item.LAYOUT_TOP);

The following sections describe the behavior of these layout directives more thoroughly.

10.9.1 Row Breaks

The layout algorithm generally attempts to place an Item in a Form on the same row as the previous Item, unless certain conditions occur that cause a "row break." A row break should be distinguished from a line break. When there is a row break, the next Item is placed at the beginning of a new row in the Form instead of being placed in the same line as the previous Item. In contrast, a line break occurs inside an Item and usually causes the Item to be taller in size.

Applications can add forced row breaks by using line feed characters ('\n'; U+000A) in an unlocked StringItem (these are discussed below) or by adding layout directives LAYOUT_NEWLINE_BEFORE or LAYOUT_NEWLINE_AFTER to Items. The presence of a newline directive does not cause an additional row break if there is one already present, but a line feed character always creates a row break.

By default, ChoiceGroup, DateField, Gauge, and TextField Items are presented on their own rows. An application must set the LAYOUT_2 directive in these Items to remove the automatic row breaks from them and to allow several Items on the same row. Still, the device may dictate that the item is always presented on a row by itself.

// textField1 and dateField1 do not have
// LAYOUT_2 set. They are presented
// in their own lines.

textField2.setLayout(Item.LAYOUT_2);
dateField2.setLayout(Item.LAYOUT_2);

Line breaks occur inside the Item area. For example, text in a TextField can be wrapped to multiple lines causing the TextField to consume more vertical space from Form. This kind of automatic content wrapping is done by the device. An application can also add manual line breaks to a TextField by placing a line feed character ("\n") in the String that is given as a parameter to the TextField. Thus, it depends on the context in which the text is used whether line feed characters will cause a row break in a Form or just a line break inside an Item.

10.9.2 Label Layout

Label positioning is dictated by the device. Labels can be presented in the same line with the Item or on a line before the Item. A device implementation may, for example, have a break (row or line) before every Item that has a label. Also, a label may be restricted to one line only. If this is the case, labels that contain line breaks might be truncated at the line break and cause the rest of the label not to be shown.

The label is counted as part of an Item size whenever the label is presented within the same content area as the Item. On the other hand, if the device dictates that a label be presented in the margin of a Form, then the label is not counted as part of the size of the Item.

10.9.3 Current Alignment

The layout algorithm has a concept of current alignment. Current alignment can have the value left, center, or right. The current alignment changes when the layout algorithm encounters an Item that has one of the layout alignment directives LAYOUT_LEFT, LAYOUT_CENTER, or LAYOUT_RIGHT. If none of these directives is present in any Item, the current layout directive does not change. This rule has the effect of grouping the contents of the Form into sequences of consecutive Items sharing an alignment value. When the layout algorithm encounters an Item with a differing layout alignment directive, then there is an automatic row break before the Item. The current alignment is maintained internally in the Form and does not affect the layout value as reported by the getLayout method.

item1.setLayout(Item.LAYOUT_LEFT);
// item2 uses current alignment
item3.setLayout(Item.LAYOUT_RIGHT);
// item4 uses current alignment
item5.setLayout(Item.LAYOUT_CENTER);
// item6 uses current alignment

Form also has an initial value for current alignment that is dictated by the device implementation. This initial value is used until an Item is laid out that explicitly defines any horizontal layout alignment directives. The initial value of current alignment can be LAYOUT_LEFT or LAYOUT_RIGHT. It is LAYOUT_LEFT if left-to-right item layout policy is used in a device and LAYOUT_RIGHT for right-to-left layout. Since the device implementation dictates the layout policy of a Form, this policy cannot change within the same Form. The device may, for example, choose the policy based on the natural language used in the user interface of a device. For example, English devices use left-to-right, and Arabic devices use right-to-left (see Figure 10.2.)

Figure 10.2. Item layout policy dictated by the device implementation

Since the initial value of current alignment is based on the Form layout policy, the current alignment at the start of the layout algorithm is based on the default alignment value of the given layout policy. For example, in Arabic user interfaces, right-to-left aligned content is most common.

10.9.4 Item Sizing

Items have two explicit size concepts: the minimum size and preferred size. Both refer to the total size (height and width) that an item requires when it is presented on the display. The size includes the Item's content and the necessary internal margins. Also, the label for the Item is included in these sizes if the device implementation renders the label so that it affects the layout. The Form layout algorithm decides which of the sizes are used when the Item is laid out.

The sizes can be dynamic since they are dependent on the contents of the Item. The minimum size is the smallest size at which the Item can function and display its contents, though perhaps not optimally. The preferred size is the size that allows an item to fully present its contents. Both of the sizes are defined by the device implementation for each built-in Item and by the application for each CustomItem and Spacer.

An application can also lock the preferred size of each Item by calling the method setPreferredSize. The minimum size cannot be locked, so the implementation can enforce certain minimum dimensions for Items.

When an Item is created, its preferred size is unlocked, and its size is calculated by the device implementation as described above.

The application can also lock one dimension of the preferred size and leave the other dimension unlocked. If the content changes, the size on the unlocked dimension is recomputed to reflect the new contents, but the size on the locked dimension remains unchanged. For example, if the application calls setPreferredSize(50, -1), the preferred width will be locked at 50 pixels and the preferred height would be computed based on the content of the Item. Similarly, if the application calls setPreferredSize(-1, 60), the preferred height will be locked at 60 pixels and the preferred width would be computed based on the contents of the Item. This feature is particularly useful for Items with textual content that can be line-wrapped; examples of such Items include StringItem and TextField.

Items also have an implicit maximum size provided by the implementation. The maximum width is typically based on the width of the screen space available to a Form. Since Forms can scroll vertically, the maximum height should typically not be limited by the height of the available screen space.

10.9.5 Row Filling

If the device implementation has not dictated otherwise, and if space permits two adjacent Form Items, they are placed on the same row. When packing multiple Items onto a single row, the width of each Item is compared with the remaining space on the row. The preferred width of the Item is used for this unless LAYOUT_SHRINK directive has been defined for the Item. If the LAYOUT_SHRINK directive is in place, the minimum size is used instead. If the size is wider than the remaining space, then a row break occurs and the Item is placed on the next row.

After a row is detected to be full of Items, there may be leftover horizontal space that is not allocated to any Items. This remaining space of the row is proportionally distributed to the Items in that row by expanding the Item widths. The space is first allocated for Items that have LAYOUT_SHRINK (in other words, to the Items that had been sized to their minimum widths.) These Items are expanded at most to their preferred sizes. If there is still leftover horizontal space after this, the rest of the space is distributed equally to those Items that use the LAYOUT_EXPAND directive. If there are no such Items, then the free space is left to the row and the Items in the row are horizontally aligned based on the horizontal alignment value shared by the Items.

The row height is determined by the tallest Item in a row. The tallest Item is found by checking the heights of all the Items in the row. If an Item has LAYOUT_VSHRINK, its minimum height is used; otherwise, the Item's preferred height is used in this check. After the row height is known, some of the Items in the row are expanded based on their vertical layout directives. Items that use the LAYOUT_VSHRINK directive are expanded to their preferred height or to the height of the row, whichever is smaller. Items that are still shorter than the row height and that use the LAYOUT_VEXPAND directive are expanded to the height of the row. The LAYOUT_VEXPAND directive on an Item will never increase the height of a row.

Remaining Items shorter than the row height are positioned vertically within the row using the LAYOUT_TOP, LAYOUT_BOTTOM, and LAYOUT_VCENTER directives. If no vertical layout directive is specified, then the Item is aligned along the bottom of the row.

The sample code below illustrates the use of the LAYOUT_EXPAND, LAYOUT_VEXPAND, and LAYOUT_TOP directives. Figure 10.3 shows how the Items are sized using these directives. The left part of the figure indicates the state before the directives have been applied and right part indicates the result of the directives. These Items have been set using the following directives:

item1.setLayout(Item.LAYOUT_EXPAND);
item2.setLayout(Item.LAYOUT_DEFAULT);
item3.setLayout(Item.LAYOUT_EXPAND);
item4.setLayout(Item.LAYOUT_TOP);
item5.setLayout(Item.LAYOUT_DEFAULT)
item6.setLayout(Item.LAYOUT_VEXPAND);
Figure 10.3. Applying vertical and horizontal layout directives

On the first Form row, item1 and item3 are horizontally expanded so that all empty space in the row is divided between these items. On the second row, item6 is first vertically expanded to the entire row height, and then item4 is aligned to the top of the row.

10.9.6 Spacer

Spacer is an Item whose only purpose is to add empty space to the Form layout. This can be done because Spacer allows its minimum size to be set. The minimum width is useful for allocating flexible amounts of space between Items in the same row of a Form.

The example below illustrates the use of a horizontal Spacer.

StringItem left = StringItem(null,
                             "left");
Spacer spacer = new Spacer(10, 2);
StringItem right = StringItem(null,
                             "right");

// Have spacer expand horizontally
spacer.setLayout(Item.LAYOUT_EXPAND);

Note that the minimum height can be used for enforcing a particular minimum height in a row. For an unlocked Spacer, the preferred width is also the same as the minimum width set by the application.


10.10 New for MIDP 2.0

We have marked a number of topics in this chapter as New! with an icon in the book margin. Here is a summary of the most important new high-level user interface features of MIDP 2.0 described in this chapter.

Classes TextBox and TextField have been improved to better control the display and input behavior by:

  • adding the ability to set a hint for the initial input character set from an extensible set of Unicode subsets (see the setInitialInputMode method),

  • adding a constraint to restrict the input of decimal numbers, including decimal point fraction digits (see the setConstraints method with the DECIMAL constraint),

  • adding constraint modifiers PASSWORD, SENSITIVE, and NON_PREDICTIVE that restrict how the values are displayed or cached (see the setConstraints method), and

  • adding constraint modifier hints to indicate that the first letter or each word or sentence should be capitalized (see the setConstraints method).

The functionality of the Form and Item classes has been significantly enhanced, as follows:

  • There are more directives to specify the layout of each Item relative to the previous and successive Item. The options include positioning left, right, center, top, vcenter, and bottom; vertical and horizontal expansion and shrinking; and the control of line breaks (see the getLayout and setLayout methods).

  • Spacer functionality has been added to provide a way to create empty spaces in the Form layout (see the Spacer class).

  • New appearance modes plain, button, or hyperlink are available for StringItems and ImageItems.

  • Commands can be added and removed from individual Items (see the addCommand and removeCommand methods).

  • Interface ItemCommandListener can be used for defining context-sensitive command actions for Items (see the setItemCommandListener method).

  • Default command can be defined for each Item (see the setDefaultCommand method).

  • It is possible for a particular Item in a Form to be made current and brought into view of the user (see the Display.setCurrentItem method).

  • There is an ability to delete all of the Items in a Form using a single method call (see the deleteAll method).

  • Customized, application-specific Item types can be defined using the new class CustomItem.

Strings and StringItems displayed in Forms have been enhanced to allow:

  • appearance modes for Strings to be plain, button, or hyperlink (see the constructor and getAppearanceMode methods), and

  • the setting and getting of the Font for a String (see the setFont and getFont methods).

Images and ImageItems used in Forms now allow:

  • appearance modes for Images to be plain, button, or hyperlink (see the constructor and getAppearanceMode methods), and

  • Images used in Forms to be mutable (see the constructor and setImage methods).

The Gauge class has been enhanced with explicit support for busy indicators to support:

  • continuous visual effects being automatically updated by the system, and

  • incremental visual effects by being updated by the application (see the setValue and setMaxValue methods).

Class ChoiceGroup and interface Choice have been updated with the addition of:

  • a pop-up mode that is similar to exclusive choice except that the visual presentation shows the selected element and the list pops up only to select another element (see the constructor),

  • the ability to set and get the Font of each element (see the setFont and getFont methods), and

  • the ability to delete all of the elements in the ChoiceGroup with a single method (see the deleteAll method).


Chapter 11. MIDP Low-Level User Interface Libraries

While the high-level user interface API provides maximum portability and development ease, some applications require greater control over the user interface.

The MIDP low-level user interface API is designed for applications that need precise placement and control of graphic elements as well as access to low-level input events. Typical examples of application components that might utilize the low-level user interface API are a game board, a chart object, or a graph.

Using the low-level user interface API, an application can:

  • control precisely what is drawn on the display,

  • handle primitive events like key presses and key releases, and

  • access concrete keys and other input devices.

Applications that program to the low-level user interface API can be portable if the application uses only the standard features; applications should stick to the platform-independent part of the low-level API whenever possible. This means that applications should not directly assume the presence of any keys other than those defined in class Canvas. Also, applications should inquire about the size of the display and adjust their behavior accordingly.


11.1 The Canvas API

To directly use the display and the low-level user interface API, the developer uses the Graphics and Canvas classes. The Canvas class provides the display surface, its dimensions, and callbacks used to handle key and pointer events and to paint the display when requested. The methods of this class must be overridden by the developer to respond to events and to paint the screen when requested.

The Graphics class provides methods to paint lines, rectangles, arcs, text, and images to a Canvas or an Image.

The combination of the event-handling capabilities of the Canvas and the drawing capabilities of the Graphics class allows applications to have complete control over the application region of the screen. These low-level classes can be used, for example, to create new screens, implement highly interactive games, and manipulate images to provide rich and compelling displays for J2ME devices.

11.1.1 Canvas Dimensions

A Canvas does not necessarily have access to the entire screen of a J2ME device. Certain areas of the screen may be reserved for other purposes such as displaying network and battery information. In addition, the use of a title, Ticker, and Commands will further reduce the area available to a Canvas.

The current dimensions of a Canvas can be obtained by calling the methods getWidth and getHeight. Furthermore, the sizeChanged method of class Canvas is called whenever the dimensions of the Canvas change, thereby allowing it to update its layout based on the new size.

If an application needs to have as much screen space as possible, the setFullScreenMode method may be called to maximize the available area. When full screen mode is enabled, the Ticker and title are not shown even if they have been added to the Canvas. Commands are still shown, although the device may minimize the space used to display them; some devices may also hide system status indicators to maximize the area available for the Canvas.

11.1.2 Redrawing Mechanism

The application is responsible for redrawing the screen whenever repainting is requested. The application implements the paint method in its subclass of Canvas. Painting of the screen is done on demand so that the device can optimize the use of graphics and screen resources, for example, by coalescing several repaint requests into a single call to the paint method of class Canvas.

Requests to repaint the screen are made automatically by the device as needed; for example, when a Canvas is first shown or when a system dialog has been shown in front of the Canvas and then dismissed. The application itself may also request a repaint of the entire display by calling the repaint method of the Canvas object. If only part of the screen needs to be updated, another repaint method can be given the location, width, and height of the region that needs to be updated.

When the paint method is called, the clip region of the provided Graphics object corresponds to the region that needs to be painted (see Section 11.3.2, "Clipping.") The paint method is responsible for rendering every pixel within the clip region and should not make assumptions about the current state of the pixels. Rendering operations will not affect pixels that lie outside of the clip region. The Canvas cannot render on top of other items on the screen such as the areas occupied by the title or Commands.

The performance of graphic-intensive applications can be enhanced greatly by requesting repaints only for the region of the Canvas that changed, and implementing the paint method to only paint the area within the clip region.

Since painting is done asynchronously, the application might need to wait for repaint requests to be completed before it can continue. The Canvas.serviceRepaints method blocks until all of the repaint requests queued have resulted in a paint call.

If the device is double buffering the display, the Graphics.isDoubleBuffered method returns true. If so, the application need not separately buffer the drawing to get a clean update of the display. Otherwise, the application might be able to optimize its display updates by creating images before they are needed, and then drawing them to the display in its paint method. Use of images is described in Section 11.4, "Creating and Using Images."

11.1.3 Drawing Model

Graphics may be rendered either directly to the display or to an off-screen Image. The destination of the rendered graphics depends on the source of the Graphics object. A Graphics object for rendering to the display is passed to the Canvas object's paint method. This is the only way to obtain a Graphics object whose destination is the display. The applications may draw using this Graphics object only for the duration of the paint method.

A Graphics object for rendering to an off-screen image is obtained by calling the Image.getGraphics method on the desired Image. The Graphics object may be held indefinitely by the application, and drawing methods may be invoked on these Graphics objects at any time.

11.1.4 Canvas Visibility

The display on a device is shared among native applications and MIDP applications. A particular application might or might not be displayed on the screen. When the application's choice of the current screen is a Canvas, the Canvas is notified when its visibility changes. The Canvas.showNotify and Canvas.hideNotify methods are invoked automatically on the Canvas when it is shown and hidden, respectively. The application should override these methods to be informed of changes in visibility. The paint method of the Canvas is called automatically when it is made visible, so the application does not need to call repaint explicitly. Show and hide notifications are useful if, for example, the Canvas is providing an animation that it should start when shown and stop when hidden.


11.2 Low-Level API for Events in Canvases

11.2.1 Key Events

If the application needs to handle key events in its Canvas, it must override the Canvas methods keyPressed, keyReleased, and keyRepeated. When a key is pressed, the keyPressed method is called with the key code. If the key is held down long enough to repeat, the keyRepeated method is called for each repeated keyCode. When the key is released, the keyReleased method is called. Some devices might not support repeating keys, and if not, the keyRepeated method is never called. The application can check the availability of repeat actions by calling the method Canvas.hasRepeatEvents.

MIDP target devices are required to support the ITU-T telephone keys. Key codes are defined in the Canvas class for the digits 0 through 9, *, and #. Although an implementation may provide additional keys, applications relying on these keys may not be portable. For portable applications, the action key mappings described below should be used whenever possible, since other key codes are device-specific.

11.2.2 Action Keys

The Canvas class has methods for handling portable action events (also known as game actions) from the low-level user interface. The API defines a set of action events: UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C, and GAME_D. The device maps the action events to suitable key codes on the device; multiple keys may map to each game action. For example, a device with four navigation keys and a SELECT key in the middle could use those keys for mapping the action events, but it may also use the keys on the numeric keypad (such as 2, 4, 5, 6, and 8).

An application should determine the appropriate action for a given key code by calling the method Canvas.getGameAction. If the logic of the application is based on the values returned by this method, the application is portable and runs regardless of the keypad design.

The mapping between keys and the abstract action events does not change during the execution of an application. One of the device-specific key codes mapped to a particular action can be retrieved with the method Canvas.getKeyCode. However, since several keys may be mapped to a single action, comparing key events to these key codes is not recommended and Canvas.getGameAction should be used instead.

11.2.3 Pointer Events

The Canvas class has methods that the application can override to handle pointer events. Pointer events are events that are generated from a pointing device such as a stylus. If the application needs to handle pointer events, it must override and implement the methods pointerPressed, pointerReleased, and pointerDragged.

Not all MIDP target devices support pointer events, and therefore the pointer methods might never be called. The application can check whether the pointer and pointer motion events are available by calling Canvas.hasPointerEvents and Canvas.hasPointerMotionEvents.


11.3 Graphics

All graphical operations are performed using a Graphics object. This object encapsulates a context for drawing to a particular target entity, including the current drawing color, clip region, line style, and so on.

11.3.1 Coordinate System

The coordinate system's default origin is located at the upper-left corner, with the numeric values of the x-coordinates monotonically increasing from left to right, and the numeric values of the y-coordinates monotonically increasing from top to bottom.

Applications may assume that the horizontal and vertical values of the coordinate system represent equal distances on the actual device display. If the shape of the pixels of the device is significantly different from square, the device does the required coordinate transformation.

The coordinate system represents the locations of pixels, not the pixels themselves. Pixels have a width and height equal to 1 and extend down and to the left of their locating point. For example, the pixel in the upper-left corner of the display is defined as (0,0) and covers the area where 0 <= x < 1 and 0 <= y < 1. All coordinates are specified as integers. (See Figure 11.1.)

Figure 11.1. Pixel coordinate system showing the pixel at (4,3)

11.3.2 Clipping

Each Graphics object has a single rectangular clip region; only those pixels within the clip region are modified by graphics operations. Operations are provided for intersecting the current clip rectangle with a given rectangle (Graphics.clipRect) and for setting the current clip rectangle outright (Graphics.setClip). The methods Graphics.getClipWidth, Graphics.getClipHeight, Graphics.getClipX, and Graphics.getClipY are used for obtaining the current clip region.

11.3.3 Translation

The coordinate system described above can be translated independently for each Graphics object. Translation is useful when a series of rendering operations need to be performed relative to some arbitrary point. Instead of recomputing the parameters for each rendering operation relative to the point, the origin can be translated to the point's location so that the rendering operations are performed relative to the new origin.

The method Graphics.translate moves the location of the origin by the specified horizontal and vertical offsets. All subsequent operations for that Graphics object will be performed relative to the translated origin. The current origin can be retrieved using the methods Graphics.getTranslateX and Graphics.getTranslateY.

Since the translation offsets are relative to the current origin, multiple translation operations have a cumulative effect. For example, calling translate(20, 50) followed by translate(3, 7) has the same effect as calling translate(23, 57).

Translation does not affect the physical location of the clip region; that is, it contains the same set of pixels before and after translation. However, since the methods for retrieving the clip region are in terms of the current coordinate system, their return values may change to reflect the new origin.

11.3.4 Color Model

Both color and gray-scale models are supported concurrently. The 24-bit color model has eight bits for each of red, green, and blue. The current drawing color is set using the method Graphics.setColor. The current color is used for all lines, text, and fills for rectangles and arcs. Separate background and foreground colors are not supported by the low-level user interface APIs.

Few devices support a full 24 bits of color, so the device maps the color requested by the application to the nearest color that is available on the device. The device color that is mapped to a given RGB color can be determined by calling the method Graphics.getDisplayColor.

The Display.isColor method returns true if the display is capable of supporting multiple colors, and false if the display supports gray-scale or black and white only. The number of distinct color or gray levels is available by calling the method Display.numColors. The color values are converted to gray-scale values by the device. The gray-scale equivalent can be retrieved with method getGrayScale after a color has been set.

Gray-scale is supported with values within the range of 0 to 255. The current gray-scale value is set with the method Graphics.setGrayScale. The device maps the values into the number of gray levels in the display. The corresponding color is available after setting a gray-scale value by calling the method Graphics.getColor.

11.3.5 Line Styles

Lines, arcs, rectangles, and rounded rectangles can be drawn with either a SOLID or a DOTTED stroke style, as set by the Graphics.setStrokeStyle method. The stroke style does not affect the fill, text, and image operations.

For the SOLID stroke style, drawing operations are performed with a one pixel-wide pen that fills the pixel immediately below and to the right of the specified coordinate. Drawn lines touch pixels at both endpoints.

Drawing operations under the DOTTED stroke style touches a subset of pixels that would have been touched under the SOLID stroke style. The frequency and length of dots is device-dependent. The endpoints of lines and arcs might not be drawn. Similarly, the corner points of rectangles might not be drawn. Dots are drawn by painting with the current color, and spaces between dots are left untouched.

11.3.6 Fonts

Each Graphics object has an associated Font object that is used for text rendering operations. The methods Graphics.setFont and Graphics.getFont are used to set and retrieve the current Font. Calling the method Graphics.setFont(null) restores the default font, which can be obtained by calling the method Font.getDefaultFont.

The Font.getFont method returns the Font object associated with a given set of style, size, and face attributes. The following attributes can be used to request a Font (from the Font class):

  • Size: SMALL, MEDIUM, LARGE

  • Face: PROPORTIONAL, MONOSPACE, SYSTEM

  • Style: PLAIN, BOLD, ITALIC, UNDERLINED

It is up to the device to select a device font that most closely matches the requested attributes. J2ME devices typically have a limited number of fonts with a fixed set of styles, sizes, and faces; therefore, several attribute combinations may be mapped to the same device font.

The Font class also provides methods to access font metrics. These metrics allow an application to precisely place text relative to other graphics. The Font class methods charWidth, charsWidth, stringWidth, and substringWidth can be used to determine the widths of strings, characters, and arrays of characters. Vertical metrics can be obtained using the methods getHeight and getBaselinePosition. The white space for inter line and inter character spacing is included in the metrics, and is below and to the right of the characters, respectively.


11.4 Creating and Using Images

11.4.1 Immutable Images

Images in a MIDP implementation may be either immutable or mutable. Immutable Images can be created directly from resource files, binary data, RGB data, or other Images. Once created, the contents of an immutable Image cannot be changed.

  • The Image.createImage(String name) method is used to create an immutable Image from binary data in a resource file bundled with the application in the application's JAR file. The name must begin with "/" and include the full name of the binary file within the JAR file.

  • The Image.createImage(byte[], int offset, int length) method is used to create an immutable Image from binary data contained in a byte array.

  • The Image.createImage(Image image) method is used to create an immutable Image from another Image (which could be either mutable or immutable).

  • The Image.createImage(java.io.InputStream stream) method is used to create an immutable Image from a stream of binary data.

  • The Image.createImage(Image image, int x, int y, int width, int height, int transform) method is used to create an immutable Image from the transformed region of another Image (which could be either mutable or immutable).

  • The Image.createRGBImage(int[] rgb, int width, int height, boolean alpha) method is used to create an immutable Image from an array of RGB color values, either with or without alpha channel data.

If binary image data is used to create an Image, it must be in a format that is supported by the device. Though some devices may optionally support additional formats, all devices must support Portable Network Graphics (PNG) format as specified by the W3C-PNG (Portable Network Graphics) Specification, Version 1.0. W3C Recommendation, October 1, 1996. This specification is available at http://www.w3.org/TR/REC-png.html and as RFC 2083, available at http://www.ietf.org/rfc/rfc2083.txt.

11.4.2 Mutable Images

Mutable Images are created with specific dimensions and can be modified as needed. Mutable Images are created with the method Image.createImage(int width, int height) and are initially filled with white pixels. The Image has the same characteristics as the display of the device: for example, color or gray-scale, and the number of available colors or gray levels.

The Image.getGraphics method returns a Graphics object that can be used for drawing into the Image. All normal Graphics methods operate on the Image, and multiple Graphics objects can be obtained if needed.

11.4.3 Transparency and Alpha Blending

Mutable Images are fully opaque, but immutable Images may contain transparent pixels. When an Image with transparency is drawn, the pixels that are transparent are not rendered, and the corresponding pixels in the target Image are left unchanged.

Some devices may also support alpha channel blending. This feature allows pixels to vary progressively from opaque to transparent, therefore allowing an Image to be blended with the target Image. Alpha blending is useful for creating special effects such as fog, smoke, and shadows.

11.4.4 Getting RGB Data

The getRGB method obtains RGB color values from a rectangular region of an Image. The color values are stored in a provided array of integers, with each color value stored in one element of the array.

getRGB(int[] rgb, int offset, int scanlength, int x, int y,
       int width, int height)

The offset parameter specifies the index at which to store the color value for the first pixel in the first row of the region. The scanlength parameter controls the number of elements in the RGB array between the first pixel of successive rows of the region. The absolute value of scanlength must be at least as large as the width of the region; this requirement prevents multiple rows from storing color values in the same elements of the array.

Color values are returned using the same form as the setColor method (0xAARRGGBB) and are subject to the display limitations of the device. Therefore, several pixels may indicate the same color value even though they are different colors in the original image data. For example, red, green, and blue pixels may be represented by the same shade of gray on a device that does not have color display capabilities.

The alpha channel byte for all of the color values will be 0xFF if the Image is opaque. If the Image is transparent, the alpha channel byte will be either 0xFF or 0x00, depending on the opacity of the pixel; the alpha channel value may vary between 0x00 and 0xFF on devices that support alpha blending.

In the following example, the offset is 2, so color value for the first pixel in the first row is stored in the array element with index 2. The scanlength is 6, so the index for the first pixel of the second row is obtained by adding 6 to the offset; the index for the first pixel of the third row is obtained by adding 6 once again. (Refer to Figure 11.2.)

int[] rgb = new int[21];
img.getRGB(rgb, 2, 6, 4, 2, 5, 3);
Figure 11.2. Example of the getRGB method

11.4.5 Anchor Points

Drawing operations that involve text or Images use anchor points to control their placement. The anchor points correspond to well-defined locations within the content to be rendered. For each rendering operation, the application specifies which anchor point is to be used and the (x,y) location in the Graphics coordinate system where that anchor point should appear. By using anchor points, the placement of text and Images is greatly simplified and tedious layout calculations are not needed.

Anchor points are defined using three horizontal constants and three vertical constants, thereby defining nine unique anchor points. A vertical constant and a horizontal constant are combined by logically OR-ing them to specify the desired anchor point.

For Image rendering operations, the Graphics class defines the anchor point constants shown in Figure 11.3.

Figure 11.3. The anchor points for image rendering

As shown in Figure 11.4, the same anchor point constants are used for text rendering operations except for the VCENTER constant. Since the vertical center of text is somewhat ambiguous, this constant is replaced with the BASELINE constant for text rendering. Note that the overall bounding area of the text includes any inter character and inter line spacing.

Figure 11.4. The anchor points for text rendering

    [ Team LiB ]


11.5 Drawing Primitives

The Graphics class provides various low-level drawing primitives. In general, drawing is started by calling the various methods of the Graphics object to set the color, translation, and clipping. Methods are available for drawing lines, various shapes, text, and Images. Each of the drawing primitives is explained next, along with a figure that illustrates their operation.

11.5.1 Drawing Lines

The Graphics.drawLine method draws a line from a starting point (x1,y1) to an ending point (x2,y2). The pixels are set to the value of the current color value. The lines are drawn with the current stroke style (see Section 11.3.5, "Line Styles.")

drawLine(int x1, int y1, int x2, int y2)

Since a pixel extends below and to the right of its point, the overall width and height of the line are one pixel larger than the difference between the two x values and the two y values, respectively. Thus, one pixel is drawn if (x1,y1) and (x2,y2) are identical.

Figure 11.5 shows the result of the following code:

g.drawLine(4, 1, 19, 7);
Figure 11.5. Example of the drawLine method

11.5.2 Drawing and Filling Arcs

The Graphics.drawArc method draws the outline of a circular or elliptical arc bounded by the a rectangle whose origin is (x,y) and whose size is specified by the width and height. The arc is drawn using the current color and stroke style, starting at startAngle degrees and extending for arcAngle degrees. The start angle is interpreted such that 0 degrees is at the 3 o'clock position. A positive angle indicates a counter-clockwise rotation, while a negative value indicates a clockwise rotation. See the following example code and Figure 11.6.

drawArc(int x, int y, int width, int height, int startAngle,
         int arcAngle)
Figure 11.6. Example of the drawArc method

The entire arc covers an area width+1 pixels wide by height+1 pixels tall. Nothing is drawn if either width or height is less than zero or if arcAngle is zero.

The angles are specified relative to the non-square extents of the bounding rectangle such that 45 degrees always falls on the line from the center of the ellipse to the upper-right corner of the bounding rectangle. As a result, if the bounding rectangle is noticeably longer in one axis than the other, the angles to the start and end of the arc segment are skewed farther along the longer axis of the bounds.

Figure 11.6 on the previous page shows an arc drawn starting at 45 degrees and extending for 315 degrees.

The Graphics.fillArc method draws and fills a circular or elliptical arc bounded by the specified rectangle. The filled region consists of the "pie wedge" region bounded by the arc segment as if drawn by drawArc, the radius extending from the center to this arc at startAngle degrees, and the radius extending from the center to this arc at startAngle + arcAngle degrees.

fillArc(int x, int y, int width, int height, int startAngle,
        int arcAngle)

Figure 11.7 shows the result of the following code:

g.fillArc(4, 1, 19, 7, 45, 315);
Figure 11.7. Example of the fillArc method

11.5.3 Drawing and Filling Rectangles

The Graphics.drawRect method draws a rectangle with the current color and stroke style. The upper-left corner of the resulting rectangle is located at (x,y) and covers an area width+1 pixels wide by height+1 pixels tall. Nothing is drawn if either width or height is less than zero.

drawRect(int x, int y, int width, int height)

Figure 11.8 shows the result of the following code:

g.drawRect(5, 2, 15, 8)
Figure 11.8. Example of the drawRect method

The Graphics.fillRect method fills rectangles with the current color. The upper-left corner of the resulting rectangle is located at (x,y) and covers an area width pixels wide by height pixels tall. Nothing is drawn if either width or height is less than one.

fillRect(int x, int y, int width, int height)

Figure 11.9 shows the result of the following code:

g.fillRect(5, 2, 15, 8);
Figure 11.9. Example of the fillRect method

11.5.4 Drawing and Filling Rounded Rectangles

The Graphics.drawRoundRect method draws a rectangle with rounded corners in the current color and stroke style. The resulting rectangle covers an area width+1 pixels wide by height+1 pixels tall. If either width or height is less than zero, nothing is drawn. The corners are rounded using a curve whose diameter measurements are arcWidth and arcHeight.

drawRoundRect(int x, int y, int width, int height, int arcWidth,
              int arcHeight)

Figure 11.10 shows the result of the following code:

g.drawRoundRect(4, 2, 16, 8, 6, 6);
Figure 11.10. Example of the drawRoundRect method

The Graphics.fillRoundRect method fills rectangles with rounded corners in the current color. If either width or height is less than zero, nothing is drawn.

fillRoundRect(int x, int y, int width, int height, int arcWidth,
              int arcHeight)

Figure 11.11 shows the result of the following code:

g.fillRoundRect(4, 2, 16, 8, 6, 6);
Figure 11.11. Example of the fillRoundRect method

11.5.5 Filling Triangles

The Graphics.fillTriangle method fills a triangle with the current color. The triangle is specified using three (x,y) coordinates which may be listed in any order.

fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)

Figure 11.12 shows the result of the following code:

g.fillTriangle(4, 2, 1, 14, 20, 10);
Figure 11.12. Example of the fillTriangle method

11.5.6 Drawing Text

Methods are provided for drawing text in the form of a single character, an array of characters, a string, or a portion of a string. The characters are rendered using the current drawing color of the Graphics object, and pixels within and around the characters are left unchanged.

drawChars(char[] ch, int offset, int length, int x, int y,
          int anchor)
drawChar(char ch, int x, int y, int anchor)
drawString(String s, int x, int y, int anchor)
drawSubstring(String s, int offset, int length, int x, int y,
             int anchor)

Character and line spacing are included in the values returned in the Font.stringWidth and Font.getHeight method calls. The inter line and inter character space is below and to the right of the pixels belonging to the characters drawn. Reasonable vertical spacing is achieved simply by adding the font height to the y-position of subsequent lines.

11.5.7 Drawing Images

Images can be drawn using the drawImage and drawRegion methods. The drawImage method is the simpler of the two and simply renders an entire Image at a specified location. Both methods use an anchor point to control where the image data is to be drawn.

[View full width]

drawImage(Image img, int x, int y, int anchor)
drawRegion(Image img, int x_src, int y_src, int width, int height, int transform, int x,
  int y, int anchor)

The drawImage method renders an entire Image at a location specified by x, y, and anchor. Figure 11.13 shows the result of the following example code:

drawImage(image, 11, 10, Graphics.RIGHT | Graphics.BOTTOM);
Figure 11.13. Example of the drawImage method

The drawRegion method is more complex. It renders a specific region in the source Image with one of several transforms applied. The transforms are defined in the Sprite class of the Game API and they provide rotations in 90-degree increments, with or without a mirror image across the vertical axis. (See Figure 11.14.)

Figure 11.14. Transforms for drawing Images

Figure 11.15 shows the result of the following example code. (Note that the anchor point is evaluated in terms of the region to be drawn after the transform has been applied.)

drawRegion(image, 1, 1, 6, 4, Sprite.TRANS_ROT90,
          7, 7, Graphics.RIGHT | Graphics.BOTTOM);
Figure 11.15. Example of the drawRegion method

11.5.8 Drawing RGB Data

The drawRGB method draws RGB color values to a rectangular region. The color values are provided in the form of an array of integers, with each element of the array containing one color value. The color values are drawn to a specified target region that is specified using a location, width, and height.

drawRGB(int[] rgb, int offset, int scanlength, int x, int y,
        int width, int height, boolean processAlpha)

The offset parameter specifies the index of the color value for the first pixel in the first row of the target region. The scanlength parameter controls the number of elements in the RGB array between the first pixel of successive rows of the target region. Any scanlength value can be used provided that the operation will not result in an invalid array index.

Color values are specified using the same form as the setColor method (0xAARRGGBB). The method's processAlpha parameter controls whether or not the alpha value (upper 8 bits) of each element is processed. If the alpha value is processed, the pixel will only be drawn if the alpha value is fully opaque (0xFF). For devices that support alpha blending, the pixel is blended with the target image based on the alpha value.

In the following code example, the offset is 2, so the color value for the first pixel in the first row corresponds to the array element with index 2. (Refer to Figure 11.16.) The scanlength is 7, so the index for the first pixel of the second row is obtained by adding 7 to the offset. The index for the first pixel of the third row is obtained by adding 7 once again.

int[] rgb = {
    0x848484, 0x4A4A4A, 0xBDBDBD, 0xFFFFFF, 0x4A4A4A, 0xDEDEDE,
    0xBDBDBD, 0x848484, 0x848484, 0x4A4A4A, 0xFFFFFF, 0x4A4A4A,
    0xBDBDBD, 0x848484, 0xFFFFFF, 0x848484, 0xDEDEDE, 0xBDBDBD,
    0xDEDEDE, 0xFFFFFF, 0xBDBDBD};
g.drawRGB(rgb, 2, 7, 4, 2, 5, 3, false);
Figure 11.16. Example of the drawRGB method

11.5.9 Copying an Area of Pixels

The copyArea method copies a region of pixels from one location to another within the target Image. This method is useful for scrolling a region of pixels without having to render the pixels again. This method cannot be invoked on the screen Graphics object.

void copyArea(int x_src, int y_src, int width, int height,
              int x_dest, int y_dest, int anchor)

The source region is defined by the parameters x_src, y_src, width, and height. The contents of the region are copied to a region of the same dimensions at the location defined by x_dest, y_dest, and anchor.

The source and destination regions specified by this method may overlap; the implementation is responsible for copying the pixel data in the appropriate manner so that the rendered pixels appear to be a snapshot of the source pixels prior to the copy operation.

Figure 11.17 shows the result of the following line of code:

g.copyArea(4, 2, 6, 4, 18, 3, Graphics.TOP | Graphics.RIGHT);
Figure 11.17. Example of the copyArea method

    [ Team LiB ]


11.6 New for MIDP 2.0

We have marked a number of topics in this chapter as New! with an icon in the book margin. Here is a summary of the most important new low-level user interface features of MIDP 2.0.

The low-level user interface has been improved to allow more control and easier programming of Canvas and Image level actions. Significant additions are support for alpha blending and for manipulating Images as arrays of pixel values.

The Canvas class has been changed as follows:

  • A full screen mode has been added that allows the maximum display to be used for application graphics (see the setFullScreenMode method.)

  • The methods for setting the Ticker and title have been moved to Displayable so that these features can be used in Canvas objects as well.

The Graphics class has been improved with:

  • the ability to draw a rectangular portion of the source Image with image transformation including rotation and mirroring (see the drawRegion method),

  • the ability to copy of pixels within an off-screen Image (see the copyArea method),

  • the ability to fill triangles, which is useful when filling irregularly shaped areas (see the fillTriangle method),

  • the ability to draw pixels into the Image from an array of RGB pixel values, possibly with alpha values (see the drawRGB method), and

  • the ability to return the color that will be used in the display (see the getDisplayColor method).

The Image class has been extended to allow easier creation of Image objects by adding methods for:

  • creating an Image from a subregion of an existing Image and with a specified rotation and mirroring transform (see the appropriate createImage method),

  • creating an immutable Image from an InputStream (support for PNG input streams is required; see the createImage(InputStream) method),

  • creating an immutable Image from an array of RGB values, possibly with alpha values (see the createRGBImage method), and

  • retrieving the RGB and alpha pixels values from an Image as an array (see the getRGB method).


Chapter 12. MIDP Game API

Game applications have proven to be one of the most popular uses for Java 2 Micro Edition, so a dedicated Game API is provided in Mobile Information Device Profile version 2.0 to facilitate game development. This API provides several benefits to the game developer. First, it simplifies game development and provides an environment that is more familiar to game developers. Second, it reduces application size and complexity by performing operations that would otherwise be implemented by the application. Third, because the API can be implemented using native code, it can also improve performance of the frequently used game routines.

As with the low-level user interface APIs, applications that use the Game API must be written carefully in order to ensure portability. Device characteristics such as screen size, color depth, and key availability must be accounted for by the developer if application portability is desired.


12.1 The GameCanvas API

The Canvas class was designed for applications that are event-driven; that is, the user interface is updated in response to a user input, such as selecting an option or pressing a soft key. However, game applications are generally time-driven and continue to run and update the display whether or not the user provides input. To overcome this difference, the GameCanvas class provides a game-centric model for accessing the display and checking for key inputs.

Game applications typically employ a single thread to run the game. This thread executes a main loop, shown in Figure 12.1, that repeatedly checks for user input, implements logic to update the state of the game, and then updates the user interface to reflect the new state. Unlike Canvas, the GameCanvas class provides methods that directly support this programming model.

Figure 12.1. Game loop flowchart

12.1.1 Key Polling

The GameCanvas class also provides the ability to poll the status of the keys instead of having to implement callback methods to process each key event. Key polling allows all of the application's key handling logic to be coded together and executed at the appropriate point in the game loop. It also enables simultaneous key presses to be detected on devices that support them.

The getKeyStates method returns the key state in the form of an integer value in which each bit indicates whether a specific key is pressed or has been pressed since the last invocation of the getKeyStates method. This latching behavior allows very quick key presses to be detected even if the game loop is running fairly slowly. If the current state of the keys is desired without the latching behavior, the getKeyStates method can be called twice.

To determine whether or not a specific key is pressed, the integer value is AND-ed with one of the key polling constants defined in GameCanvas, as shown in the following example:

int keyStates = getKeyStates();
if ((keyStates & UP_PRESSED) != 0) yPosition--;
if ((keyStates & DOWN_PRESSED) != 0) yPosition++;
if ((keyStates & FIRE_PRESSED) != 0) fireRocket();

12.1.2 Screen Buffer

Unlike Canvas (which shares screen resources with other applications), each GameCanvas object has its own dedicated screen buffer, which the developer can draw on at any time using a Graphics object. Graphics objects are obtained by calling method getGraphics. Multiple Graphics objects can be created if desired.

Changes to the screen buffer contents are limited to rendering calls made by the application, so the buffer can be updated incrementally instead of being completely rendered for each frame.

Synchronous methods are provided for flushing the contents of the buffer to the physical display, so continuous animations are much easier to implement than with the asynchronous repainting model of the Canvas class. The flushGraphics methods flush the contents of the buffer to the physical display, either for the entire buffer or for a specific region of the buffer. These methods do nothing if the GameCanvas is not currently shown.


12.2 Layers

The Layer class is an abstract class that represents a basic visual entity that can be rendered on the screen. A Layer has defined rectangular bounds, and it can be either visible or invisible. A Layer can be rendered using any Graphics object by calling its paint method.

The game API defines two Layer subclasses: Sprite and TiledLayer. Unfortunately, class Layer cannot be directly subclassed by the developers, since this would compromise the ability to improve performance through the use of native code in the implementation of the Game API.

Subclasses of class Layer can be drawn at any time using the paint method. The Layer will be drawn on the Graphics object according to the current state information maintained by the Layer object (that is, position, visibility, and so forth.) The Layer object is drawn at its current position relative to the current origin of the Graphics object. Erasing the Layer is always the responsibility of the code outside the Layer class.


12.3 Sprites

A Sprite is a basic visual element whose appearance is provided by one of several frames stored in an Image. The developer can control which frame is used to render the Sprite, thereby enabling animation effects. Several transforms such as flipping and rotation can also be applied to a Sprite to further vary its appearance. As with all Layer subclasses, a Sprite's location can be changed, and it can also be made visible or invisible.

12.3.1 Frames

The raw frames used to render a Sprite are provided in a single Image object, which may be mutable or immutable. If more than one frame is used, they are packed into the Image as a series of equally-sized frames. The frames are defined when the Sprite is instantiated; they can also be updated by calling the setImage method.

As shown in Figure 12.2, the same set of frames may be stored in several different arrangements depending on what is most convenient for the game developer. The implementation automatically determines how the frames are arranged based on the dimensions of the frames and those of the Image. The width of the Image must be an integer multiple of the frame width, and the height of the Image must be an integer multiple of the frame height.

Figure 12.2. Frames can be arranged in various ways within an Image

The Image is divided into frames whose dimensions are dictated by the frameWidth and frameHeight parameters in the Sprite's constructor. Each frame within the Image is assigned a unique index number; the frame located in the upper-left corner of the Image is assigned an index of 0. (See Figure 12.3.) The remaining frames are then numbered consecutively in row-major order (indices are assigned across the first row, then the second row, and so on.) The getRawFrameCount method returns the total number of raw frames.

Figure 12.3. Each frame in the Image is assigned an index

In following example, a Sprite is created by dividing an Image into 8 frames that are 16 pixels wide and 23 pixels high:

Image carFrames = Image.createImage("/carframes.png");
Sprite car = new Sprite(carFrames, 16, 23);

12.3.2 Frame Sequence

The frame sequence of a Sprite defines an ordered list of frames to be displayed. The default frame sequence mirrors the list of available frames, so there is a direct mapping between the sequence index and the corresponding frame index. This also means that the length of the default frame sequence is equal to the number of raw frames. For example, if a Sprite has 4 frames, its default frame sequence is {0, 1, 2, 3}.

The developer must explicitly switch the current frame in the frame sequence. This may be accomplished by calling the Sprite.setFrame, Sprite.prevFrame, or Sprite.nextFrame methods. The method Sprite.setFrame sets the current index in the sequence array. The method Sprite.prevFrame decrements the current index, wrapping around to the last sequence element if necessary. The method Sprite.nextFrame increments the current index, wrapping around to the first sequence element if necessary. Note that these methods always operate on the sequence index, not frame indices, although the sequence indices and the frame indices are interchangeable if the default frame sequence is used.

If desired, an arbitrary frame sequence may be defined for a Sprite. The frame sequence is defined using an array of integers whereby each element references a valid frame index. The array must contain at least one element, and each element must contain a valid frame index. The setFrameSequence method is used to set the frame sequence; passing this method null as the frame sequence restores the default frame sequence.

By defining a new frame sequence, the developer can conveniently display the Sprite's frames in any order desired; frames may be repeated, omitted, shown in reverse order, and so forth. For example, Figure 12.4 shows a special frame sequence that is used when the car explodes. Note that certain frames are repeated so that they are shown for a longer period of time.

int[] explosionSequence = {1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7};
car.setFrameSequence(explosionSequence);
Figure 12.4. Example of a special frame sequence

12.3.3 Reference Pixel

As a subclass of Layer, class Sprite inherits various methods for setting and retrieving object location such as the methods setPosition(x,y), getX(), and getY(). These methods all define position in terms of the upper-left corner of the Sprite's visual bounds; however, in some cases, it is more convenient to define the Sprite's position in terms of an arbitrary pixel within its frame, especially if transforms are applied to the Sprite.

Therefore, Sprite includes the concept of a reference pixel. The reference pixel is defined by specifying its location in the Sprite's untransformed frame using the defineReferencePixel method. By default, the reference pixel is defined to be the pixel at (0,0) in the frame. If desired, the reference pixel may be defined outside of the frame's bounds.

As shown in Figure 12.5, the reference pixel can be thought of as having a pushpin in its center. In this example, we define the reference pixel to be a pixel in the center of the car's front axle:

car.defineReferencePixel(8, 5);
Figure 12.5. The reference pixel with a pushpin in its center

Once defined, this pushpin may be used to set and query the location of the Sprite. The getRefPixelX and getRefPixelY methods can be used to query the location of the pushpin in the painter's coordinate system. The setRefPixelPosition method can be used to position the Sprite by specifying where the pushpin should be located in the painter's coordinate system.

12.3.4 Transforms

Various transforms can be applied to a Sprite. The available transforms include rotations in multiples of 90 degrees combined with mirroring about the vertical axis. The transforms are identical to those provided for Image rendering. (See Section 11.5.7, "Drawing Images.") A Sprite's transform is set by calling its setTransform method.

When a transform is applied, the Sprite is automatically positioned so that its reference pixel appears stationary in the painter's coordinate system. Thus, the reference pixel's pushpin effectively becomes the center of the transform operation. Since the reference pixel does not move, the values returned by getRefPixelX and getRefPixelY remain the same; however, the values returned by getX and getY may change to reflect the movement of the Sprite's upper left corner.

For the car example shown in Figure 12.5, the reference pixel is located closer to the front, which makes the rear of the car appear to slide as it is rotated by 90 degrees in Figure 12.6.

Figure 12.6. The reference pixel acts as the center for transforms applied to a Sprite

    [ Team LiB ]


12.4 TiledLayer

A TiledLayer is a Layer that is composed of a grid of cells that can be filled with a set of tile images. This technique is commonly used in 2D gaming platforms to create very large scrolling backgrounds without the need for an extremely large Image. The use of animated tiles allows numerous cells of a TiledLayer to be animated quickly and easily.

12.4.1 Tiles

As with a Sprite's frames, the tiles used to fill the TiledLayer's cells are provided in a single Image object which may be mutable or immutable. The Image is broken up into a series of equal-sized tiles whose dimensions are specified along with the Image.

Each tile is assigned a unique index number, as shown in Figure 12.7. The tile located in the upper-left corner of the Image is assigned an index of 1 (unlike Sprite where the first frame is given an index of 0). The remaining tiles are then numbered consecutively in row-major order (indices are assigned across the first row, then the second row, and so on). These tiles are regarded as static tiles because there is a fixed link between the tile and the image data associated with it. The static tile set is created when the TiledLayer is instantiated; it can also be updated at any time using the setStaticTileSet method.

Figure 12.7. A TiledLayer's static tile set is obtained from an Image

In addition to the static tile set, the developer can also define several animated tiles. An animated tile's appearance is provided by the static tile to which it is linked. This link can be updated dynamically, thereby allowing the developer to change the appearance of several cells without having to update the contents of each cell individually. This technique is very useful for animating large repeating areas without having to explicitly change the contents of numerous cells.

Animated tiles are created using the createAnimatedTile method, which returns the index to be used for the new animated tile. The animated tile indices are always negative and consecutive, beginning with –1. The associated static tile that provides the animated tile's appearance is specified when the animated tile is created, and can also be dynamically updated using the setAnimatedTile method.

12.4.2 Cells

The TiledLayer's grid is made up of equal-sized cells; the number of rows and columns in the grid are specified in the constructor, and the physical size of the cells is defined by the size of the tiles. The contents of each cell is specified by the means of a tile index; a positive tile index refers to a static tile, and a negative tile index refers to an animated tile. A tile index of 0 indicates that the cell is empty, meaning that the cell is fully transparent and nothing is drawn in that area when the TiledLayer is rendered. By default, all cells contain tile index 0.

The contents of cells may be changed individually using the method setCell and as rectangular groups of cells using the method fillCells. Several cells may contain the same tile; however, a single cell cannot contain more than one tile.

The following example illustrates how a simple background can be created using a TiledLayer. The setCell and fillCells methods are used to set the contents of the cells as shown in Figure 12.8. By default, the contents of the cells is 0, which makes them transparent.

tiles.fillCells(0, 0, 8, 1, 1);
tiles.fillCells(0, 0, 1, 6, 1);
tiles.setCell(2, 2, -1);
tiles.setCell(7, 3, -1);
tiles.setCell(3, 5, -1);
Figure 12.8. The TiledLayer's cells filled with the desired tile indices

With the cell contents set, the appearance of the TiledLayer would be as shown in Figure 12.9. Note that since static tile 2 is linked to animated tile –1, it appears in each of the cells that contain –1.

Figure 12.9. Appearance of the TiledLayer

To animate the coin, a different static tile is linked to the animated tile using the setAnimatedTile method. In this example, the animated tile –1 is linked to static tile 5 instead of static tile 2, and the resulting appearance is shown in Figure 12.10.

myTileLayer.setAnimatedTile(-1, 5);
Figure 12.10. An update to an animated tile is reflected in all cells that reference it

    [ Team LiB ]


12.5 LayerManager

The LayerManager manages a series of Layers and simplifies the rendering process by automatically drawing the correct regions of each Layer in the appropriate order.

The LayerManager maintains an ordered list to which Layers can be appended, inserted, and removed. A Layer's index correlates to its z-order; the layer at index 0 is closest to the user while the Layer with the highest index is furthest away from the user. The indices are always contiguous; that is, if a Layer is removed, the indices of subsequent Layers will be adjusted to maintain continuity.

The LayerManager class provides several features that control how the game's Layers are rendered on the screen. The size of the view window controls how large the user's view will be, and is usually fixed at a size that is appropriate for the device's screen.

The position of the view window can also be adjusted relative to the LayerManager's coordinate system. Changing the position of the view window enables effects such as scrolling or panning the user's view. For example, to scroll to the right, simply move the view window's location to the right.

In the example shown in Figure 12.11, the view window is set to a region that is 120 pixels wide, 120 pixels high, and located at (102, 40) in the LayerManager's coordinate system.

layerMgr.setViewWindow(102, 40, 120, 120);
Figure 12.11. Setting the view window

The paint method of LayerManager class includes an (x,y) location that controls where the contents of the view window are rendered relative to the screen. Changing these parameters does not ch ange the contents of the view window; it simply changes the location where the view window is drawn on the screen. Note that this location is relative to the origin of the Graphics object, and thus it is subject to the translation attributes of the Graphics object.

For example, if a game uses the top of the screen to display the current score (Figure 12.12), the view window may be rendered at (0, 12) to provide space for the score.

layerMgr.paint(g, 0, 12);
Figure 12.12. The contents of the view window drawn at a specific location

    [ Team LiB ]


12.6 Collision Detection

Collision detection is a key feature of the Game API, enabling the developers to quickly and easily determine whether two elements of a game have collided or not.

The collision detection methods are provided in the Sprite class, and they allow the developer to detect a collision between a Sprite and either a TiledLayer, an Image, or another Sprite.

12.6.1 Collision Rectangle

Sprites have a defined collision rectangle that indicates the region to be included for collision detection. By default, this region corresponds to the overall bounds of the Sprite. However, it can be redefined to cover any rectangular region as needed.

A special collision rectangle allows areas of a Sprite to be excluded from the collision detection process. For example, a jet fighter Sprite may include a vapor trail coming from the engines; however, a missile colliding with this part of the Sprite should not be considered as hitting the aircraft. By defining a collision rectangle that includes only aircraft and excludes the vapor trail (see Figure 12.13), selective collision detection can be easily achieved.

Figure 12.13. Setting a collision rectangle

The collision rectangle is automatically updated to reflect any transforms that are applied to the Sprite. Therefore, there is no need to modify the collision rectangle when a transform operation is performed.

12.6.2 Pixel-Level Detection

The collision detection methods allow the developer to specify boundary-level or pixel-level detection. Boundary-level detection checks if the collision rectangles of the two elements are intersecting or not, and it is the simplest and fastest detection scheme. However, many elements are likely to be non rectangular in nature, so boundary-level detection may not be sufficient.

To overcome this problem, the developer may request pixel-level detection. Used in conjunction with transparent image data, this detection scheme checks whether an opaque pixel in the first element is touching an opaque pixel in the second element. Thus, the transparent area around the opaque area is excluded from the detection process, and a collision is detected only when the opaque areas appear to be touching. Any transforms applied to a Sprite are automatically accounted for when checking for collisions.

Pixel-level detection is performed only within the collision rectangles of the two elements. Thus, touching opaque pixels will not result in a collision if either one is outside of the element's collision rectangle.

For platforms that support alpha channel blending, any alpha value less than fully opaque is considered to be transparent for the purposes of collision detection.

Figure 12.14 and Figure 12.15 illustrate the differences between pixel-level and boundary-level collision detection. The gray area around Duke represents transparent pixels. Boundary-level detection indicates a collision whenever the boundaries of the two images are touching; pixel-level detection indicates a collision only when opaque pixels are touching.

Figure 12.14. Boundary-level collision detection

Figure 12.15. Pixel-level collision detection

    [ Team LiB ]


12.7 Sample Code: A Simple Game

This example illustrates how the APIs discussed in this chapter can be used to form a simple game. The user controls a car that is always moving forward at a constant speed and can be turned 90 degrees clockwise or counterclockwise. The object of the game is to drive around the track and collect as many coins as possible without hitting any of the walls. (See Figure 12.16 on the next page.)

Figure 12.16. A screen shot from the simple game

The car is implemented using a Sprite that can be rotated in 90-degree increments using the appropriate transform. Special frame sequences are used to show just the first frame or to animate through the explosion frames.

The track and the coins are implemented using TiledLayers. Most of the cells in the tiled layers are left empty so that the dark gray background is seen. A static tile is used to form the walls of the track, and an animated tile is used to display the spinning coins.

Two separate TiledLayers are used to simplify the collision detection code. Collision detection provides a simple way to determine whether the car has collided with a non-empty cell in either of the TiledLayers. If the collision was with the coins, some simple code determines which cells containing the coins can be removed and the score can be accurately updated.

Note that this code example is simplified to demonstrate the use of the game API; a real application would require additional code to appropriately handle application starting and pausing, game restarts, displaying the score, multiple levels, and so on.

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
import java.io.*;

/**
 * Simple car game that demonstrates
 * the MIDP 2.0 Game API
 **/
public class SimpleGame extends MIDlet {

    public SimpleGame() {
    }

    protected void startApp() throws MIDletStateChangeException {

        try {
            Display.getDisplay(this).setCurrent(
                                  new SimpleGameCanvas(this));
        } catch (IOException e) {
            // Cannot load game
        }
    }

    protected void pauseApp() {
    }

    protected void destroyApp(boolean unconditional)
        throws MIDletStateChangeException {
    }
}

/**
 * GameCanvas subclass for the game
 */
public class SimpleGameCanvas extends GameCanvas
                                 implements Runnable {

    // Car directions
    static final int DIR_UP = 0;
    static final int DIR_RIGHT = 1;
    static final int DIR_DOWN = 2;
    static final int DIR_LEFT = 3;

    // Transform to be used for each car direction
    static final int[] carTrans = { Sprite.TRANS_NONE,
                                    Sprite.TRANS_ROT90,
                                    Sprite.TRANS_ROT180,
                                    Sprite.TRANS_ROT270 };
    MIDlet parent;

    Sprite car;
    TiledLayer track;
    TiledLayer coins;

    int[] normalSequence = {0};
    int[] explosionSequence = { 1, 1, 2, 2, 3, 3, 4, 4, 4,
                                5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
                                7, 7, 7, 7, 7, 7 };

    public SimpleGameCanvas(MIDlet parentMIDlet)
    throws IOException {
        super(true);
        parent = parentMIDlet;

        // Create the car, define its reference pixel, and set
        // the frame sequence that shows just the first frame
        Image carFrames = Image.createImage("/carframes.png");
        car = new Sprite(carFrames, 16, 23);
        car.defineReferencePixel(8, 5);
        car.setFrameSequence(normalSequence);
        car.setPosition(30, 240);
        // Create the track and set the cell values
        Image tiles = Image.createImage("/tiles.png");
        track = new TiledLayer(30, 30, tiles, 16, 16);

        track.fillCells(0, 0, 30, 1, 1);
        track.fillCells(0, 29, 30, 1, 1);
        track.fillCells(0, 1, 1, 28, 1);
        track.fillCells(29, 1, 1, 28, 1);
        track.fillCells(4, 15, 22, 1, 1);

        coins = new TiledLayer(30, 30, tiles, 16, 16);
        coins.createAnimatedTile(2);
        coins.setCell(3, 3, -1);
        coins.setCell(6, 20, -1);
        coins.setCell(10, 24, -1);
        coins.setCell(16, 18, -1);
        coins.setCell(23, 3, -1);
        coins.setCell(3, 16, -1);
        coins.setCell(16, 25, -1);
    }
    public void showNotify() {
        // Start a thread to run the game
        new Thread(this).start();
    }

    public void run() {

        // Get graphics for rendering to the screen buffer
        Graphics g = getGraphics();

        // Create a layer manager to render the layers and
        // add the layers in the appropriate order
        LayerManager mgr = new LayerManager();
        mgr.append(car);
        mgr.append(track);
        mgr.append(coins);

        // Determine the view window size and its vertical
        // location on the screen
        int viewOffset = g.getFont().getHeight();
        int viewWidth = getWidth();
        int viewHeight = getHeight() - viewOffset;

        // Game state information
        boolean exploding = false;
        int lastKeys = 0;
        int dir =0;
        int vx = 0;
        int vy = 0;
        int coinsLeft = 7;

        // Counter used to animate the coins
        int coinTile = 0;

        int score = 1;

        while (true) {
            // Update current car direction based on key input
            int keys = getKeyStates();
            if (keys != lastKeys) {
                if ((keys & LEFT_PRESSED) != 0) {
                    dir--;
                }
                else if ((keys & RIGHT_PRESSED) != 0) {
                    dir++;
                }
                dir = (dir + 4) & 0x03;
                car.setTransform(carTrans[dir]);
                lastKeys = keys;
            }

            // Check whether the car is exploding
            if (exploding) {
                // Check whether the end of the explosion
                // sequence has been reached
                if (car.getFrame() == explosionSequence.length-1) {
                    return;
                }
                // Show the next frame in the explosion sequence
                car.nextFrame();
            } else {
                // Update the car's velocities based on
                // the current direction
                switch (dir) {
                    case DIR_UP:
                        if (vy > -32) vy--;
                        if (vx > 0) vx--;
                        if (vx < 0) vx++;
                        break;
                    case DIR_RIGHT:
                        if (vx < 32) vx++;
                        if (vy > 0) vy--;
                        if (vy < 0) vy++;
                        break;
                    case DIR_DOWN:
                        if (vy < 32) vy++;
                        if (vx > 0) vx--;
                        if (vx < 0) vx++;
                        break;
                    case DIR_LEFT:
                        if (vx > -32) vx--;
                        if (vy > 0) vy--;
                        if (vy < 0) vy++;
                        break;
                }

                // Move the car based on its velocities
                car.move(vx >> 4, vy >> 4);

                 // check whether we hit the track wall
                if (car.collidesWith(track, true)) {
                    // Start the explosion sequence
                    car.setFrameSequence(explosionSequence);
                    exploding = true;
                }
                // check whether the car hit a coin
                if (car.collidesWith(coins, true)) {
                    // Determine which cells intersect with car
                    // Get the overall bounds of the car
                    int xmin = car.getX();
                    int xmax = xmin + car.getWidth();
                    int ymin = car.getY();
                    int ymax = ymin + car.getHeight();

                    // Convert car bounds to grid coordinates
                    // (divide by 16)
                    xmin >>= 4;
                    xmax >>= 4;
                    ymin >>= 4;
                    ymax >>= 4;

                 // Check each cell that intersects the car's bounds
                                for (int i = xmin; i <= xmax; i++) {
                        for (int j = ymin; j <= ymax; j++) {
                            // See if the cell is not empty
                            if (coins.getCell(i, j) != 0) {
                                // Remove the cell's coin
                                coins.setCell(i, j, 0);
                                coinsLeft--;
                                // Increment the score
                                score++;
                            }
                        }
                    }
                    if (coinsLeft == 0) {
                        // Game over, player won
                    }
                }
            }

            // Animate the coins by updating the static tile
            // that is linked to the animated tile
            coins.setAnimatedTile(-1, 2 + ((coinTile++ >> 2)
                                            & 0x03));

            // Adjust the view window so that the car is always
            // in the center of the screen
            mgr.setViewWindow(car.getRefPixelX()-(viewWidth/2),
                             car.getRefPixelY()-(viewHeight/2),
                             viewWidth, viewHeight);
            // Fill the background with dark gray
            g.setGrayScale(45);
            g.fillRect(0,viewOffset, viewWidth, viewHeight);

            // Render the layers (coins, track, and car) at the
            // appropriate location on the screen
            mgr.paint(g, 0, viewOffset);

            // Render the score
            g.setColor(0xFFFFFF);
            g.fillRect(0,0, viewWidth, viewOffset);
            g.setColor(0x000000);

            // Flush the screen buffer to the display
            flushGraphics();
        }
    }
}


12.8 New for MIDP 2.0

The Game API is an entirely new feature in MIDP 2.0. With the Game API, application developers can simplify the development of game applications by using a programming paradigm that is well suited to game applications. Since the Game API provides many operations that would otherwise be implemented by the application, the API can significantly reduce the size and complexity of game applications.


Chapter 13. MIDP Sound API

This chapter introduces the Sound API of MIDP 2.0. In the first version of the MIDP Specification, sound support was minimal. With the release of the MIDP Specification version 2.0, this area has now been significantly enhanced. A well-defined, scalable architecture for sound and multimedia has been created for devices running J2ME, with primary emphasis on mobile phones using the Mobile Information Device Profile. In addition to offering basic sound programming support in MIDP 2.0, an optional package called the Mobile Media API has been created to enable generic multimedia functionality. A diverse set of applications will benefit from sound and media support in J2ME devices. Examples of such applications include games, speech, and multimedia applications.

The purpose of this chapter is to give the reader an overview of the MIDP 2.0 Sound API and the complementary optional package, the Mobile Media API (MMAPI), created by the Java Community Process effort JSR 135.


13.1 Overview of the MIDP 2.0 Sound API

13.1.1 MIDP Media Support

MIDP devices range from low-end mass-market phones with basic sound support to high-end media phones with advanced audio and video rendering capabilities. To accommodate these diverse configurations and multimedia processing capabilities, an API with a high level of abstraction and support for optional features is needed. The central goal of the specification work for the Sound API was to address the wide range of application areas. As a result, two API sets were developed:

  • MIDP 2.0 Sound API

  • Mobile Media API (MMAPI)

The division into two interoperable API sets arose from the fact that some devices are very resource-constrained. It may not be feasible to support a full range of multimedia types, such as video, on some mobile phones. As a result, not all MIDP 2.0 target devices are required to support the full generality of the Mobile Media API, such as the ability to support custom protocols and content types.

MIDP Sound API

The MIDP 2.0 Sound API is intended for resource-constrained devices such as mass-market mobile phones. The basic level of sound support mandated for all devices is the presence of monophonic buzzer tones. This API is a directly compatible subset of the full Mobile Media API. Furthermore, due to its building block nature, this subset API can be adopted to other J2ME profiles that require sound support.

Mobile Media API

The full Mobile Media API is intended for J2ME devices with advanced sound and multimedia capabilities. The target devices for the Mobile Media API include powerful mobile phones, as well as PDAs and set-top boxes.

Applications

Sound and media are a key feature in many applications. Games, music applications, user interface tones, and alerts are examples of application areas that will benefit from the MIDP Sound API.

In the following sections, the MIDP Sound API is discussed in more detail. In Section 13.4, "Enhanced Media Support Using the Mobile Media API," a more detailed look at the MMAPI is provided.

13.1.2 Design Goals

The main design goals for the MIDP Sound API were:

  • Playback of time-based audio and ringing tones. This is the main feature of the sound API. The basic target of the design is to let applications play back media in various formats.

  • Independence of specific media formats and protocols. The sound API itself is not targeted to support any specific media format or protocol. There are no hard-coded format descriptors in the API. Rather, the formats are handled as MIME types. This provides extensibility and support for future formats. However, in MIDP Specification version 2.0, a set of mandatory protocols and content formats for audio have been defined to ensure interoperability.

  • Support for tone generation. There is an internal tone sequence format and a method to play single tones. An internal tone sequence format has been added to the API in order to let MIDP applications create simple monophonic tone sequences on their own.

13.1.3 Requirements

The design goals stated in the previous section form a set of requirements, which have to be fulfilled by all devices implementing the sound API. The requirements that were defined in MIDP Specification version 2.0 include

  • low footprint audio playback,

  • protocol and content format independence,

  • support for tone generation,

  • support for general media flow controls (start, stop, etc.),

  • support for media-specific type controls (such as volume control), and

  • support for capability queries.

This subset differs from the full Mobile Media API requirements in the following ways:

  • The MIDP 2.0 sound API is audio-only. It excludes all Control classes that are specific to MIDI, video, or graphics.

  • The sound API does not support custom protocols (via custom DataSource classes).

Scalability

It is important to note that the building block subset used in MIDP 2.0 is a proper subset of the full Mobile Media API (MMAPI), and it is fully forward-compatible with the MMAPI. In order to add the full Mobile Media API functionality to a MIDP 2.0 device, one only needs to implement the additional classes and methods from that API.

Formats and protocols

In the context of sound and multimedia processing, protocol handling refers to reading data from a source (such as a file or streaming server) into a media processing system. Content handling usually requires processing the media data (parsing or decoding, for example) and rendering the media to output devices such as a loudspeaker. The MIDP 2.0 sound API is defined in a manner that enables the custom formats and protocols. At the very minimum, the devices must be able to play tones, either via dedicated hardware or via software algorithm. Furthermore, MIDP 2.0 devices

  • must support tone generation in the media package,

  • must support 8-bit, 8 KHz, mono linear PCM wav format if any sampled sound support is provided,

  • may include support for additional sampled sound formats,

  • must support Scalable Polyphony MIDI (SP-MIDI) and SP-MIDI Device 5-to-24 Note Profile if any synthetic sound support is provided, and

  • may include support for additional MIDI formats.

In other words, the basic requirement for sound support for all mobile information devices is monophonic tone sequencing. Both synthetic audio (MIDI) and sampled audio are optional, and these features may be implemented if the device provides corresponding hardware or software support.

The audio content used by MIDlets normally originates in a MIDP 2.0 implementation from three different sources: 1) over-the-air via HTTP 1.1 protocol, 2) via the Record Management System (RMS), or 3) from a JAR file. It should be noted that whereas the sound API supports a generic protocol naming mechanism, MIDP 2.0 only supports HTTP 1.1. With the use of the full Mobile Media API, custom protocols for media streaming can be introduced.

13.1.4 MIDP Sound Architecture

The MIDP sound architecture design was based on a set of design goals and requirements agreed to by the MIDP 2.0 expert group. A baseline for sound support that all devices must follow was created. Optional features may be supported, but they are not mandated by the MIDP Specification.

The framework of sound and media support in MIDP 2.0 consists of three main components: Manager, Player, and Controls. Figure 13.1 shows an overview of the architecture. A simple way to understand the functionality of the Sound API is to think of the functionality of an ordinary video player (VCR). Class Manager represents the VCR user who loads the tape into the VCR and controls the overall use. The technical functionalities of the VCR, such as playing, stopping, rewinding, or recording, are represented by the Player class. Finally, the Control classes define the actions that determine how the VCR is controlled, for example, by adjusting the volume or by initiating the recording mode.

Figure 13.1. Overview of MIDP Sound API Architecture

In more technical terms, the functionality of the sound architecture can be described as follows. Class Manager is the access point for obtaining system-dependent resources such as Player objects for multimedia processing. Applications use the Manager class to request Players and to query supported content types and supported protocols. The Manager class also includes a method to play simple tones.

A Player is an object that is used to control and render media that is specific to the content type of the data. The application may obtain a Player by giving a locator string or an InputStream and a content type to the Manager class.

A Control is an interface that is used to implement all of the different controls a Player might have. An application can query a Player to check which controls it supports and then ask for a specific Control—for example, VolumeControl—to control volume.


13.2 Player Creation and Management

In this section, the process of creating and managing sound in a MIDP 2.0 application is described. The functionality of classes Manager and Player are described, and simple application examples are provided to illustrate the details of the API.

Figure 13.2 shows the class diagram of the MIDP 2.0 Sound API. (Interfaces are shown in italic font.)

Figure 13.2. Class diagram of the MIDP Sound API

13.2.1 Managing a Media Framework

The entry point to the Sound API is the Manager class. Class Manager provides access to an implementation-specific mechanism for constructing Player objects. In addition, class Manager provides means for property queries of content and protocol support. For convenience, it also provides a simplified method to generate simple tones.

Property queries

The MIDP sound API provides a mechanism for querying the type of content and protocols that the device supports. The property queries are enabled by the methods Manager.getSupportedContentTypes and Manager.getSupportedProtocols.

For example, if the given protocol is "http:", then the supported content types that can be played back with the http protocol will be returned. If null is passed in as the protocol, all the supported content types for this device will be returned. The returned array must be non-empty; in other words, at least one content type has to be supported.

13.2.2 Creating Players for Media Data

The Player interface controls the rendering of time-based media data. It provides the methods to manage the life cycle of the Player, controls the playback progress, and obtains the presentation components.

A Player can be created using one of the two createPlayer methods of the Manager class:

// Create a Player to play back media from an InputStream
createPlayer(java.io.InputStream stream, String type)

// Create a Player from an input locator
createPlayer(String locator)

When a Player is created from an InputStream, the type argument specifies the content type of the input media. If null is given, Manager will attempt to determine the type. However, since determining the media type is non-trivial for some media types, it may not be feasible in some cases; Manager may throw a MediaException to indicate the occurrence of such a situation.

A Player can also be created using a locator. In this case, a locator string is given in URI syntax that describes the media content.

After the Player object is created, it will enter the STARTED state when the program calls the method Player.start. This method will start the playback as soon as possible and will return when the playback is started. The playback will continue in the background and will stop automatically when the end of media is reached. The MIDP Sound API Player states are described in detail in Figure 13-3 and in "Player life cycle" on page 204.

Figure 13.3. MIDP Sound API Player state diagram

Data sources for media

Content types identify the type of media data for Player objects when the Player is created using an InputStream. These content types are defined to be the registered MIME types[1] . In addition, there are some user-defined types that generally follow the MIME syntax (RFC 2045, RFC 2046).

[1] See http://www.iana.org/assignments/media-types/ for details of registered MIME types for media.

For example, here are a few common content types:

  • Tone sequences: audio/x-tone-seq

  • Wave audio files: audio/x-wav

  • AU audio files: audio/basic

  • MP3 audio files: audio/mpeg

  • MIDI files: audio/midi

When a Player is created using a media locator, the locator is specified in URI syntax defined in the following form:

<scheme>:<scheme-specific-part>

The "scheme" part of the locator string identifies the name of the protocol being used to deliver the data. For instance, "http://webserver/music.mid" is an example of a valid locator string.

Player life cycle

A typical media player features the basic commands (or state transition methods) for starting and stopping media playback. In resource-constrained devices, however, special care must be taken to optimize the media playback process for applications. Therefore, the MIDP 2.0 media player architecture features additional states, which are described in more detail below.

Figure 13.3 shows a state diagram that illustrates the MIDP 2.0 Player life cycle. The Player object has five states: UNREALIZED, REALIZED, PREFETCHED, STARTED, and CLOSED. The purpose of these life-cycle states is to provide programmatic control over the use of media resources and potentially time-consuming operations. For example, when a Player is first constructed, it's in the UNREALIZED state. When the state changes from UNREALIZED to REALIZED, the Player performs the communication necessary to locate all of the resources it needs to function (such as communicating with a server or a file system). The realize method allows an application to initiate this potentially time-consuming process at an appropriate time.

Typically, a Player moves from the UNREALIZED state to the REALIZED state, then to the PREFETCHED state, and finally on to the STARTED state. A Player stops when it reaches the end of media or when the stop method is invoked. When that happens, the Player moves from the STARTED state back to the PREFETCHED state. Upon calling the Player.stop method, the playback position in the file does not change, so calling Player.start again will continue the playback from the same location. In Figure 13.3, the gray-shaded boxes represent the reservation of audio resource in hardware.

The basic use of a Player only requires the Player.start and Player.stop methods. However, in order to fully utilize all the functionality of the Player, parameters must be set up appropriately to manage the life-cycle states, and the state transition methods should be used correctly to advance between the various Player states.

Additional Player functionalities include looping of audio using the setLoopCount method, and obtaining or setting the current position of media playback using the getMediaTime and setMediaTime methods. Furthermore, the getDuration method can be used to query the length of the media file.

PlayerListener

Class PlayerListener defines an interface that can be used for receiving asynchronous events generated by Player objects. Applications can implement this interface and register their implementations with the addPlayerListener method of class Player.

A number of standard Player events are defined in the PlayerListener interface. Event types are defined as Strings in order to support extensibility because different implementations may introduce proprietary events by adding new event types. The predefined, standard event types are as follows:

  • CLOSED. Posted when a Player is closed. The Player may be closed either by the user, or it may be closed by the system after an irrecoverable error has occurred.

  • DEVICE_AVAILABLE. Posted when the system or another higher priority application has released an exclusive device that is now available to the Player.

  • DEVICE_UNAVAILABLE. Posted when the system or another higher priority application has temporarily taken control of an exclusive device that was previously available to the Player.

  • DURATION_UPDATED. Posted when the duration of a Player is updated.

  • END_OF_MEDIA. Posted when a Player has reached the end of the media.

  • ERROR. Posted when an error had occurred.

  • STARTED. Posted when a Player is started.

  • STOPPED. Posted when a Player stops in response to the stop method call.

  • VOLUME_CHANGED. Posted when the volume of an audio device is changed.

The playerUpdate method is called to deliver an event to a registered listener when a Player event is observed.

13.2.3 Tone Generation

The minimal requirement for all MIDP 2.0 devices is to support the playback of monophonic single tones. Tone generation is important for games and other audio applications. On resource-constrained devices, this is particularly important since tone generation is likely to be the only form of audio capabilities supported.

In its simplest form, tone generation is implemented as a single buzzer or simple monophonic tone generation. This feature is enabled by two different methods in the MIDP 2.0 API.

The first possibility is to use the Manager class, which provides a method for playing back simple tones (see Section 13.2.4, "Sample Code," for an example), specified by a note and its duration. A note is given in the range of 0 to 127 inclusive. The frequency of the note can be calculated using the following formula:

SEMITONE_CONST = 17.31234049066755 = 1/(ln(2^(1/12)))
note = ln(freq/8.176)*SEMITONE_CONST
// The musical note A = MIDI note 69 (0x45) = 440 Hz.

This call is a non-blocking call. Notice that this method may utilize CPU resources significantly on devices that do not have hardware support for tone generation.

The second possibility to create sequences of single tones is to use the ToneControl API. The use of this API is discussed in more detail in Section 11.3.1.

13.2.4 Sample Code

In this section, a few simple examples are provided to illustrate tone generation and the creation of new Players using the methods of class Manager.

Example: Single tone generation
try {
    Manager.playTone(ToneControl.C4 /* note */,
                     5000           /* duration in ms */,
                     100            /* max vol */);
} catch (MediaException e) {
}
Example: Creating a player from media stored in JAR

Notice that in MIDP 2.0 the wav format is mandatory only in case the device supports sampled audio.

try {
    InputStream is = getClass().getResourceAsStream("music.wav");
    Player p = Manager.createPlayer(is, "audio/X-wav");
    p.start();
} catch (IOException ioe) {
} catch (MediaException me) {
}
Example: Creating a player from media in HTTP locator
try {
    Player p = Manager.createPlayer("http://webserver/music.mid");
    p.start();
} catch (IOException ioe) {
} catch (MediaException me) {
}

Notice that in MIDP 2.0, the MIDI format (SP-MIDI) is mandatory only when the device supports sampled audio.


13.3 Media Controls

Control objects are used for controlling content-type-specific media processing operations. The set of operations are usually functionally related. Thus a Control object provides a logical grouping of media-processing functions.

All Control classes implement the interface Controllable, and the Player interface is a subinterface of Controllable. Therefore, a Player implementation can use the Control interface to extend its media-processing functions. For example, a Player can expose a VolumeControl to allow the volume level to be set.

The javax.microedition.media.control package specifies a set of predefined Controls classes. In MIDP 2.0, two controls are specified and required: ToneControl and VolumeControl.

The Controllable interface provides a mechanism for obtaining the Controls from an object such as a Player. It provides methods to get all the supported Controls and to obtain a particular Control based on its class name.

13.3.1 ToneControl

ToneControl is an interface that enables the playback of a user-defined monotonic tone sequence. A tone sequence is specified as a list of tone duration pairs and user-defined sequence blocks. The list is packaged as an array of bytes. The setSequence method is used for defining the sequence for the ToneControl.

Here is the syntax of a tone sequence, described using an Augmented BNF notation. (See http://www.ietf.org/rfc/rfc2234 for details of the Augmented BNF notation.)

sequence              = version *1tempo_definition
                        *1resolution_definition
                        *block_definition 1*sequence_event

version               = VERSION version_number
VERSION               = byte-value
version_number        = 1      ; version # 1

tempo_definition      = TEMPO tempo_modifier
TEMPO                 = byte-value
tempo_modifier        = byte-value
        ; multiply by 4 to get the tempo (in bpm) used
        ; in the sequence.

resolution_definition = RESOLUTION resolution_unit
RESOLUTION            = byte-value
resolution_unit       = byte-value

block_definition      = BLOCK_START block_number
                          1*sequence_event
                        BLOCK_END block_number
BLOCK_START           = byte-value
BLOCK_END             = byte-value
block_number          = byte-value
        ; block_number specified in BLOCK_END has to be
        ; the same as the one in BLOCK_START

sequence_event        = tone_event / block_event /
                          volume_event / repeat_event

tone_event            = note duration
note                  = byte-value ; note to be played
duration              = byte-value ; duration of the note

block_event           = PLAY_BLOCK block_number
PLAY_BLOCK            = byte-value
block_number          = byte-value
        ; block_number must be previously defined
        ; by a full block_definition

volume_event          = SET_VOLUME volume
SET_VOLUME            = byte-value
volume                = byte-value ; new volume

repeat_event          = REPEAT multiplier tone_event
REPEAT                = byte-value
multiplier            = byte-value
        ; number of times to repeat a tone

byte-value            = -128 - 127
        ; the value of each constant and additional
        ; constraints on each parameter are specified below

Note that VERSION, TEMPO, RESOLUTION, BLOCK_START, BLOCK_END, PLAY_BLOCK, and SET_VOLUME REPEAT are predefined constants.

Example: Tone sequencing

The following example illustrates the use of tone sequencing by playing the familiar song "Mary Had a Little Lamb."

/**
 * "Mary Had A Little Lamb" has "ABAC" structure.
 * Use block to repeat "A" section.
 */
byte tempo = 30; // set tempo to 120 bpm
byte d = 8;      // eighth-note

byte C4 = ToneControl.C4;;
byte D4 = (byte)(C4 + 2); // a whole step
byte E4 = (byte)(C4 + 4); // a major third
byte G4 = (byte)(C4 + 7); // a fifth
byte rest = ToneControl.SILENCE; // rest

byte[] mySequence = {
    ToneControl.VERSION, 1,       // version 1
    ToneControl.TEMPO, tempo,     // set tempo
    ToneControl.BLOCK_START, 0,   // start define "A" section
      E4,d, D4,d, C4,d, E4,d,     // content of "A" section
      E4,d, E4,d, E4,d, rest,d,
    ToneControl.BLOCK_END, 0,     // end define "A" section
    ToneControl.PLAY_BLOCK, 0,    // play "A" section
    D4,d, D4,d, D4,d, rest,d,     // play "B" section
    E4,d, G4,d, G4,d, rest,d,
    ToneControl.PLAY_BLOCK, 0,    // repeat "A" section
    D4,d, D4,d, E4,d, D4,d, C4,d  // play "C" section
};

try {
    Player p = Manager.createPlayer(
               Manager.TONE_DEVICE_LOCATOR);
    p.realize();
    ToneControl c = (ToneControl)p.getControl("ToneControl");
    c.setSequence(mySequence);
    p.start();
} catch (IOException ioe) {
} catch (MediaException me) {
}

13.3.2 VolumeControl

VolumeControl is an interface for manipulating the audio volume of a Player object. The volume settings interface allows the output volume to be specified using an integer value that varies between 0 and 100. The level scale specifies volume in a linear scale. It ranges from 0 to 100, where 0 represents silence and 100 represents the highest volume. The mapping for producing a linear multiplicative value is implementation-dependent. Setting mute on or off does not change the volume level returned by method getLevel. If mute is true, no audio signal is produced by the Player; if mute is false, an audio signal is produced and the volume is restored. When the state of the VolumeControl changes, a VOLUME_CHANGED event is delivered to the Player through its PlayerListener.

13.3.3 Custom Controls

MIDP Specification version 2.0 defines only two custom controls: ToneControl and VolumeControl. Additional controls are available in the Mobile Media API. These features are discussed in more detail in Section 13.4, "Enhanced Media Support Using the Mobile Media API."

13.3.4 Sample Code

The sample application below defines a simple media player for sampled audio with an attached volume control. The Player is created from an InputStream. A Gauge is used for visualizing and controlling the volume of the player. Simple player functions including start, stop, and rewind are supported. Furthermore, PlayerListener events are defined for printing the player states during the execution of the program.

Note that in MIDP 2.0, the wav format is mandatory only when the device supports sampled audio.

PlayerMidlet.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * Simple music player application using the MIDP 2.0 Sound API
 */
public class PlayerMidlet extends MIDlet
        implements CommandListener, ItemStateListener {
    Display display;
    Command exitCommand = new Command("Exit", Command.EXIT, 99);
    Command stopCommand = new Command("Stop", Command.ITEM, 1);
    Command startCommand = new Command("Start", Command.ITEM, 1);
    Command rewindCommand = new Command("Rewind", Command.ITEM, 2);
    Form form;
    Source source;
    Gauge gauge;
    int itemNum;

    public PlayerMidlet() {
        display = Display.getDisplay(this);

        // Create the form
        form = new Form("MIDP 2.0 sound demo");
        form.addCommand(startCommand);
        form.addCommand(exitCommand);
        form.setCommandListener(this);

        // Set up interactive gauge for the volume control
        gauge = new Gauge("Player Volume", true, 100, 50);
        form.append(gauge);
        gauge.setLayout(0x800);
        itemNum = form.append("Value: " + gauge.getValue());
        form.setItemStateListener(this);

        // Instantiate player
        source = new Source("/sound.wav");
    }

    protected void startApp() throws MIDletStateChangeException {
        display.setCurrent(form);
    }

    protected void pauseApp() {
        source.stop();
    }

    protected void destroyApp(boolean unconditional)
            throws MIDletStateChangeException {
        source.destroy();
    }

    /**
     * Define the gauge updates
     */
    public void itemStateChanged(Item item) {
        if (item == gauge) {
            // Set the current gauge value to the player volume
            source.setLevel(gauge.getValue());
            form.delete(itemNum);
            form.append("Value: " + gauge.getValue());
        }
    }

    /**
     * Respond to commands issued on the form
     */
    public void commandAction(Command c, Displayable s) {
        if (c == stopCommand) {
            source.stop();
            form.removeCommand(stopCommand);
            form.addCommand(startCommand);
            form.addCommand(rewindCommand);
        } else if (c == startCommand) {
            source.start();
            form.removeCommand(startCommand);
            form.removeCommand(rewindCommand);
            form.addCommand(stopCommand);
        } else if (c == rewindCommand) {
            source.rewind();
            form.removeCommand(rewindCommand);
        } else if (c == exitCommand) {
            try {
                destroyApp(false);
                notifyDestroyed();
            } catch (MIDletStateChangeException e) {
            }
        }
    }
}
Source.java
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;

public class Source implements PlayerListener {

    Player p;
    VolumeControl volC;

    Source(String fileName) {

        // Define input stream to read from the sound file
        InputStream is = getClass().getResourceAsStream(fileName);

        if (is == null) {
            System.out.println("Error creating InputStream "
                               + fileName);
        }

        try {
            // Create player: give input stream and media type.
            // In this demo the sound file is in WAV format.
            p = Manager.createPlayer(is, "audio/X-wav");

            if (p == null) {
                System.out.println("Error creating Player "
                                   + fileName);
            } else {
                p.addPlayerListener(this);
                p.realize();        // Realize the player
                p.prefetch();       // Prefetch the player
                p.setLoopCount(-1); // Play indefinitely
                System.out.println("Realized Player: "
                                   + fileName);
            }
        } catch (IOException e) {
            System.out.println(e);
        } catch (MediaException e) {
            System.out.println(e);
        }
        // Obtain volume control for the player
        volC = (VolumeControl)p.getControl("VolumeControl");
    }

    public void destroy() {
        if (p != null) {
            // Close the player
            p.close();
        }
    }

    public void start() {
        if (p != null) {
            try {
                // Start the player from current media time
                p.start();
            } catch (MediaException e) {
                System.out.println(e);
            }
        }
    }

    public void stop() {
        if (p != null && p.getState() == Player.STARTED) {
            try {
                // Stop the player. Note that player
                // does not rewind to beginning when
                // stop is called
                p.stop();
            } catch (MediaException e) {
                System.out.println(e);
            }
        }
    }

    public void rewind() {
        if (p != null && p.getState() == Player.PREFETCHED) {
            try {
                // Rewind the player to beginning by setting
                // media time to a negative value
                p.setMediaTime(-1);
            } catch (MediaException e) {
                System.out.println(e);
            }
        }
    }

    public int setLevel(int level) {
        // Update the player volume
        return volC.setLevel(level);
    }

    /**
     * Define the player updates
     */
    public void playerUpdate(Player p, String event,
                             Object eventData) {

        if (event == STARTED)
            System.out.println("Player started");
        else if (event == STOPPED)
            System.out.println("Player stopped");
        else if (event == END_OF_MEDIA)
            System.out.println("Player at end of file");
        else if (event == VOLUME_CHANGED)
            System.out.println("Player volume changed");
        else if (event == CLOSED)
            System.out.println("Player closed");
    }
}


13.4 Enhanced Media Support Using the Mobile Media API

As discussed earlier in this chapter, MIDP Sound API is a subset of the Mobile Media API (MMAPI) defined by the Java Community Process effort JSR 135. MMAPI includes a lot of additional functionality that is not present in the MIDP 2.0 Sound API. The additional features introduced by the Mobile Media API include the following:

  • Custom protocols through the DataSource

  • Synchronization of multiple Players using the TimeBase interface

  • Interactive synthetic audio

  • Video and camera functionality

  • Capture and recording

  • Metadata

The scalability and optional use of the API is crucial for the successful deployment of the API in mobile devices. It is clear that not all implementations of MMAPI will support all multimedia types and input protocols. For example, some of the devices may support only playback of local audio files. The design of the MMAPI allows implementations to provide optional support for different media types and protocols.

As with the MIDP 2.0 Sound API, class Manager provides the getSupportedContentTypes and getSupportedProtocols methods to query for supported media types and protocols. An application can also attempt to create a Player from class Manager given the media input. If the content type or the protocol specified is not supported, the Player creation methods will throw an exception.

Because MMAPI is an optional package, it does not mandate any particular media types or protocols. Required types and protocols are to be determined by the appropriate profiles adopting MMAPI (for example MIDP 2.0). However, an implementation must guarantee support of at least one media type and protocol.

MMAPI also allows implementations to support optional features. For example, some implementations may support only media playback but not recording. MMAPI allows implementations to expose these optional features as applicable.

Optional features are organized as Control classes. A Player can be queried for all of its supported Controls using the method getControls or a particular type of Control using the method getControl.

MMAPI mandates support of some features for some media types. Other features are recommended while others are entirely optional. This guarantees some uniformity across different implementations. The implementation alternatives are categorized into features sets. When a Player is created for a particular type, it must follow the guidelines given in the specification and implement the appropriate Control types. The following feature sets are defined for five different types of media:

  • tone sequence (controls for built-in monophonic tone sequence format),

  • sampled audio (controls for handling sampled audio data),

  • interactive MIDI (controls for handling MIDI event streaming, for example, in games),

  • MIDI (controls for full-functionality synthetic audio applications), and

  • video (controls for video playback and still-image capture support.)

13.4.1 DataSource

Class DataSource encapsulates protocol handling. It hides the details of how the data is read from its source, and whether the data is coming from a file, streaming server, or a proprietary delivery mechanism. Class DataSource provides a set of methods to allow a Player to read data.

13.4.2 Advanced Controls

MMAPI defines a total of 12 Control classes. These Control classes are summarized in Table 13.1.

Table 13.1. Mobile Media API controls

MMAPI Controls

Overview

FramePositioningControl

Interface to control precise positioning to a video frame for Players.

GUIControl

Extends Control and is defined for controls that provide GUI functionality.

MetaDataControl

Used to retrieve metadata information included within the media streams.

MIDIControl

Provides access to MIDI rendering and transmitting devices.

PitchControl

Raises or lowers the playback pitch of audio without changing the playback speed.

RateControl

Controls the playback rate of a Player.

RecordControl

Controls the recording of media from a Player. This control records what is currently being played by the Player.

StopTimeControl

Specifies a preset stop time for a Player.

TempoControl

Controls the tempo, in musical terms, of a song.

ToneControl

Interface to enable playback of a user-defined monotonic tone sequence.

VideoControl

Controls the display of video and provides a method for taking snapshots.

VolumeControl

Interface for manipulating the audio volume of a Player.

The ToneControl and VolumeControl interfaces are specified in the MIDP 2.0 Sound API. For video and camera functionality, FramePositioningControl and GUIControl are provided. MIDI specific controls include MIDIControl for controlling a sound synthesizer using MIDI messages, PitchControl for changing the pitch in music applications (such as Karaoke), RateControl for changing the playback rate of a player, and TempoControl for controlling the playback tempo of a song. Additional controls include MetaDataControl, which allows the addition of auxiliary data related to a media stream, and StopTimeControl, which allows for setting a preset stop time for playback.

The set of controls in the MMAPI specification provides a versatile means for creating audio, MIDI, video, and camera support in MIDlets. In future releases of the API, new controls may be introduced.


13.5 New for MIDP 2.0

In the MIDP Specification version 1.0, sound support was minimal. With the release of the MIDP Specification version 2.0, sound support has been significantly extended. A well-defined, scalable Sound API has been created for devices supporting the Mobile Information Device Profile. A diverse set of applications—including games and media applications—will benefit from the MIDP 2.0 Sound API.


Chapter 14. MIDP Persistence Libraries

The MIDP Specification provides a mechanism for MIDlets to persistently store data and retrieve it later. This persistent storage mechanism, called the Record Management System (RMS), is modeled after a simple, record-oriented database. This chapter introduces the key features and characteristics of the Record Management System.


14.1 The Record Management System

Conceptually, RMS provides records and record stores, as shown in Figure 14.1. A record store is a collection of records that is persistent across multiple invocations of a MIDlet. Each record is an array of bytes. Each record in a record store can be of a different length and can each store data differently. For example, in Figure 14.1 the topmost record, Record ID 1, may contain a String followed by an int, while the second record, Record ID 5, may contain an array of short numbers.

Figure 14.1. Structure of a record store

Associated with each record in a record store is a unique identifier called the recordId. This identifier can be used to retrieve a record from the record store (see getRecord in Section 14.2.3, "Manipulating Records in a Record Store"). In Figure 14.1, "adjacent" records in the record store do not necessarily have consecutive recordIds. The underlying implementation may in fact reorganize records within the store or place two consecutively placed records in "far" apart locations. All that is guaranteed is that if a record is added to the record store, it will retain its recordId until deleted. A recordId is assigned via a monotonically, increasing-by-one algorithm. There is no provision for "wrap around" of recordIds. However, since the data type for recordIds is an integer that is capable of storing a number as large as 2,147,483,647, it is highly unlikely that a given recordId will ever be reused within a record store, especially since mobile information devices usually have limited persistent storage.

MIDlets within a MIDlet suite can access one another's record stores directly; however, no locking operations are provided by the RMS. Therefore, if a MIDlet suite uses multiple MIDlets or threads to access a record store, it is the developer's responsibility to coordinate these access operations with the synchronization primitives provided by the Java programming language. Note that the system software of the mobile information device is responsible for maintaining the integrity of RMS record stores throughout the normal use of the platform, including reboots, battery changes, and so forth. Therefore, the programmer does not have to worry about these issues.

The sharing of RMS record stores is controlled by the MIDP application model (see Section 19.1.4, "MIDlet Suite Execution Environment"). Under this model, record stores are shared by all MIDlets within a MIDlet suite but are not normally shared with other MIDlet suites. For example, in Figure 14.2, the record store called Alpha of MIDlet_Suite_1 is separate and distinct from the record store Alpha of MIDlet_Suite_2. Therefore, MIDlet_Suite_1 cannot access the record stores of MIDlet_Suite_2 and vice versa. Note that in MIDP 2.0, mechanisms were added such that a MIDlet suite can make one or more of its record stores available to MIDlets in all MIDlet suites installed on the device. This is described further in Section 14.2.2, "Shared Record Stores."

Figure 14.2. Separation of RMS name spaces

    [ Team LiB ]


14.2 Manipulating Record Stores and Records

Record stores have two basic types of operations: those that deal with manipulating the record store as a whole and those that deal with manipulating the records within the record store. A summary of different record store and record manipulation operations is provided in the following sections.

14.2.1 Manipulating a Record Store

The programmer accesses record stores by name. These names are case-sensitive and may contain between 1 and 32 Unicode characters. The name space for record stores is a flat, non-hierarchical space.[1]

[1] Note: The name space of record stores is separate from that of resources (resources are accessed by calling the method java.lang.Class.getResourceAsStream.) Thus, the name of a record store can be lexically equivalent to that of a resource, but the two are separate entities.

Within a MIDlet suite, record store names are unique. In other words, MIDlets within a MIDlet suite are not allowed to create more than one record store with the same name. On the other hand, no such restriction applies to different MIDlet suites: a MIDlet within one MIDlet suite is allowed to have a record store with the same name as a MIDlet in another MIDlet suite. In that case, the record stores are distinct and separate. A MIDlet can obtain a list of all the record stores owned by the containing MIDlet suite by calling the class static method listRecordStores of class RecordStore.

In order to access a record store, the record store must be opened first. A MIDlet can open one of its record stores with the method openRecordStore that takes two parameters: a String containing the name of the record store, and a boolean indicating whether the record store should be created if it does not exist yet. The method openRecordStore returns an object of type RecordStore, which provides access to the following methods that return information about the associated record store:

  • getName: returns a String that represents the name with which this record was opened or created.

  • getNumRecords: returns an int that represents the number of records currently in the record store.

  • getSize: returns an int that represents the current number of bytes contained in the record store.

  • getSizeAvailable: returns an int that represents the number of remaining bytes in the device that the record store could potentially occupy. Note that the number returned by this method is not a guarantee that the record store can actually grow to this size, since another MIDlet may allocate space for another record store.

  • getNextRecordID: returns an int that represents the recordId for the next record added to the record store.

  • getVersion: returns an int that represents the version of the record store. Each time a record is added, deleted, or modified in the record store, the version number of the record store is incremented by 1.

  • getLastModified: returns a long that represents the last modification time of the record store. The time returned is in the same format as used by method System.currentTimeMillis. The modification time of a record store is changed each time its version changes (see the description above.)

The two final operations on a record store are closing and deleting it. A record store is closed by invoking the method closeRecordStore. Note that a record store is not closed until all outstanding opens have been matched with a corresponding close operation. In other words, as long as there are open references to a record store, it will not be closed. When a record store is finally closed, all record listeners are removed (see Section 14.2.5, "Filtering, Comparing, Listening, and Enumerating Records"), and any attempts to perform any operations on the record store object cause a RecordStoreNotOpenException to be thrown.

A record store is deleted by passing its name as a String to the static method deleteRecordStore of class RecordStore. A record store must be closed before it can be deleted.

14.2.2 Shared Record Stores

New APIs in MIDP 2.0 allow for the explicit sharing of record stores if the MIDlet creating the record store chooses to give such permission. At the time of record store creation, a MIDlet can choose whether the record store should be available only to MIDlets within its MIDlet suite or available to all MIDlets installed on the device. If a record store is shared, the MIDlet can also choose whether MIDlets in other MIDlet suites should have read-only access or be allowed to write to the record store. There are no fine-grained access controls available for granting access to only a subset of the MIDlets on a device.

To create a shared record store, the MIDlet calls the openRecordStore method, which takes four parameters:

  • a String containing the name of the record store,

  • a boolean indicating whether the records store should be created (if it does not yet exist),

  • an integer indicating the access mode requested (shared or private), and

  • a boolean indicating whether MIDlets from other MIDlet suites are granted write access to the record store, or only read-only access.

Sharing is accomplished through the ability to name a record store created by another MIDlet suite. That is, record stores are identified using the unique name of the MIDlet suite plus the name of the record store. MIDlet suites are identified by the MIDlet-Vendor and MIDlet-Name attributes from the manifest and/or application descriptor (see Section 19.1.3, "MIDlet Attributes").

To open a shared record store from another MIDlet suite, the MIDlet calls the openRecordStore method that takes three String parameters: the name of the record store, and the vendor name and MIDlet suite name of the MIDlet suite that created the shared record store.

As described in Section 19.3.2, "MIDlet Suite Removal," when a MIDlet suite is deleted all of its record stores are also removed. This includes any shared record stores that it owns.

14.2.3 Manipulating Records in a Record Store

Within a record store, individual records can be added, retrieved, modified, and deleted. The most common methods for manipulating records are summarized below:

  • addRecord: takes a byte array, an offset, and a length as parameters. A recordId is returned for a record created from the byte array subset starting at the given offset through the given length. Note that this is a blocking operation and the method will not return until the record has been written to the underlying persistent storage.

  • deleteRecord: takes a recordId as a parameter and removes the record represented by that recordId from the record store.

  • getRecordSize: takes a recordId as a parameter and returns the size of the associated record in bytes.

  • getRecord: has two forms: The first form takes a recordId as a parameter and returns a copy of the record. The second form takes a recordId, and a user-supplied byte array and offset. This form of the method returns a copy of the record into the byte array starting at the given offset.

  • setRecord: takes a recordId, a byte array, an offset, and a length as parameters. The record identified by the recordId is overwritten from the beginning with data from a subset of the byte array subset identified by the offset and length.

14.2.4 Converting Record Data to and from Byte Arrays

Before data can be saved into a record store, it must be converted into an array of bytes. Using CLDC classes such as DataInputStream, DataOutputStream, ByteArrayInputStream, or ByteArrayOutputStream, developers can pack and unpack different data types into and out of byte arrays. As an example, consider a game MIDlet that needs to record scores and names of players. The code fragment below illustrates how such a record (byte array) might be created:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream outputStream = new DataOutputStream(baos);
// Add the score (an int) then the name of the player (a UTF)
// to the DataOutputStream.
outputStream.writeInt(score);
outputStream.writeUTF(name);
// Now, extract the byte array (record)
byte[] theRecord = baos.toByteArray();

Once the record has been created, it can be inserted into a record store using the addRecord operation introduced in Section 14.2.3, "Manipulating Records in a Record Store."

14.2.5 Filtering, Comparing, Listening, and Enumerating Records

The records of a record store may be processed in various ways. To provide programmer-defined ways to filter, search, and sort a record store, RMS provides the four Java interfaces discussed below.

The RecordFilter interface

The RecordFilter interface allows the programmer to define filters for searching records. This interface requires the programmer to supply a method called matches that accepts one record as a parameter. This method returns a boolean indicating whether or not the given record matches the user-defined search criteria. For instance, consider the following example in which a record store contains different types of records, with the type being indicated by the first byte. In this example, Integer records are indicated by the first byte being 'I'. The following filter returns true if the candidate record is an Integer record:

public class IntegerFilter implements RecordFilter {
    public boolean matches(byte[] candidate)
                   throws IllegalArgumentException {
        return candidate[0] == 'I';
    }
}
The RecordComparator interface

The RecordComparator interface allows the programmer to define comparison operations for records. This interface defines the method compare that takes two records as parameters. This method returns one of the following class-static values from the RecordComparator class:

  • EQUIVALENT: returned if the two records are considered equivalent for this sort order.

  • FOLLOWS: returned if the first record follows the second for this sort order.

  • PRECEDES: returned if the first record precedes the second for this sort order.

To carry forth the previous example, let's assume that the Integer records discussed above have the format of a record type indicator (in this case: 'I') followed by a four-byte Integer. Furthermore, let's assume that we want to sort the records in ascending order according to value of the four-byte Integer field. A record comparator to accomplish this could be written as follows (with error checking omitted):

class IntegerCompare implements RecordComparator {
    public int compare(byte[] b1, byte[] b2) {
        DataInputStream is1 = new DataInputStream(
                                  new ByteArrayInputStream(b1));
        DataInputStream is2 = new DataInputStream(
                                  new ByteArrayInputStream(b2));
        /**
         * Skip record type (1 byte), then read ints
         */
        is1.skip(1);
        is2.skip(1);
        int i1 = is1.readInt();
        int i2 = is2.readInt();
        if (i1 > i2) return RecordComparator.FOLLOWS;
        if (i1 < i2) return RecordComparator.PRECEDES;
        return RecordComparator.EQUIVALENT;
    }
}
The RecordListener interface

In order to monitor the addition and modifications of records to a record store, RMS provides the RecordListener interface. This interface defines three methods that a class must implement. Each method takes two parameters: a RecordStore and a recordID:

  • recordAdded: called when a record is added to the record store.

  • recordChanged: called when a record is modified in the record store.

  • recordDeleted: called when a record is deleted in the record store.

The following code fragment shows a simple record listener that prints out a line indicating what type of operation is being done to a record store:

/**
 * Add the listener to the record store
 */
recordStore.addRecordListener((RecordListener) new myListener());
...
public class myListener implements RecordListener {
    final private static int ADDED = 1;
    final private static int CHANGED = 2;
    final private static int DELETED = 3;

    private void handleCall(int type, RecordStore rs, int rid) {
        System.out.print("Record store " + rs.getName() +
                         " and record id " + rid +
                         " was ");
        switch (type) {
        case myListener.ADDED:
            System.out.println("added");
            break;
        case myListener.CHANGED:
            System.out.println("changed");
            break;
        case myListener.DELETED:
            System.out.println("deleted");
            break;
        }
    }

    public void recordAdded(RecordStore rs, int rid) {
        handleCall(myListener.ADDED, rs, rid);
    }
    public void recordChanged(RecordStore rs, int rid) {
        handleCall(myListener.CHANGED, rs, rid);
    }
    public void recordDeleted(RecordStore rs, int rid) {
        handleCall(myListener.DELETED, rs, rid);
    }
}
The RecordEnumerator interface

The final interface provided by RMS is the RecordEnumeration interface. A class implementing this interface provides a mechanism to enumerate over all the records in the record store. Although a developer can implement this interface, the most common usage of record enumeration is simply using the enumerateRecords provided by the RecordStore class.

The enumerateRecords method returns an instance of a class that implements the RecordEnumeration interface. It takes three parameters: a RecordComparator, a RecordFilter, and a boolean that indicates that the returned enumerator should register itself as a listener in order to keep it updated with ongoing activity on the record store. The most efficient way to get each record in a record store is to supply neither a RecordComparator nor a RecordFilter:

simpleRE = recordStore.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
    byte b[] = re.nextRecord();
    ...
}

This example would return, in an undefined order, every record in the record store while ignoring changes made to the record store by other MIDlets or threads.

A more complex example is enumerating through a subset of records in the record store and sorting them in a user-defined manner. Using our previous examples of the RecordComparator and the RecordFilter, we can construct a record enumerator that only returns the records containing Integer numbers in numerically ascending order with the following code fragment:

IntegerFilter iFilt = new IntegerFilter();
IntCompare iCompare = new IntegerCompare();
intRE = recordStore.enumerateRecords((RecordFilter)iFilt,
                                     (RecordComparator)iCompare,
                                     false);
while (IntRE.hasNextElement()) {
    byte b[] = re.nextRecord();
    ...
}

Suppose that our record store had two types of records: Integer and String, with the String records starting with an 'S' and the Integer records beginning with an 'I'. If our record store contained the following records:

Record 1: 'I', 100
Record 2: 'S', "Joy"
Record 3: 'I', 50
Record 4: 'S', "Zachary"
Record 5: 'S', "Abby"
Record 6: 'I', 25

then the enumeration returned by intRE would be Record 6, Record 3, then Record 1.


14.3 Sample Code (RMSMIDlet.java)

The following small sample application, RMSMIDlet.java, demonstrates some of the capabilities of RMS. Only the main class and one non-public implementation class of this application are shown.

The RMSMIDlet example creates two record stores called Personal and Business and allows the user to view the contents of the record store and the details of the individual records using the operations discussed in Section 14.2.1, "Manipulating a Record Store").

When the MIDlet begins, the application opens the screen that is depicted in the figure above.

If the user selects the OK command, then the content of the selected database (in this case, Personal) is shown, as depicted in the figure to the right.

If the user navigates through the MENU command and selects the DETAIL command, then the detail screen is shown. (See the figure on the next page.)

Class RMSMIDlet is implemented as a MIDlet, so its structure and functionality follows the general guidelines defined for MIDlet classes. This means that the class must implement the methods startApp, pauseApp, and destroyApp to define the behavior upon application startup, pausing, and exit, respectively.

The class also implements the CommandListener interface in order to listen to command input from the user. The implementation of class RMSMIDlet utilizes a package private (non-public) class CreateAddressBook in order to create and populate the application's database with sample address book entries.

CreateAddressBook.java

package examples.addressbook;
import java.lang.*;
import java.io.*;
import java.util.*;
import javax.microedition.rms.*;

/**
 * Static helper class that creates a record
 * store from data in an array.
 */
class CreateAddressBook {

    // Don't allow this class to be instantiated
    private CreateAddressBook() {}
    /**
     * Helper method that creates a record
     * store from data in an array.
     * Returns:
     *  true      if RMS store was created
     *  false     otherwise
     *  name      the name of the record store to create
     *  seedData  an array w/ data to seed record store
     */
    static boolean createRecordStore(String name,
                                     String[] seedData) {
        RecordStore recordStore;
        boolean ret = false;
        // Delete any previous record store with same name.
        // Silently ignore failure.
        try {
            RecordStore.deleteRecordStore(name);
        } catch (Exception rse) {}

        // Create new RMS store. If we fail, return false.
        try {
            recordStore = RecordStore.openRecordStore(name, true);
        } catch (RecordStoreException rse) {
            return ret;
        }

        ret = true; // assume success

        // Now, populate the record store with the seed data
        for (int i = 0; i < seedData.length; i += 3) {
            byte[] record = SimpleRecord.createRecord(seedData[i],
                                                     seedData[i+1],
                                                    seedData[i+2]);

            try {
                recordStore.addRecord(record, 0, record.length);
            } catch (RecordStoreException rse) {
                ret = false;
                break;
            }
        }

        // Get here when adds are complete, or an error occurred.
        // In any case, close the record store. We shouldn't
        // have a failure, so silently ignore any exceptions.
        try {
            recordStore.closeRecordStore();
        } catch (RecordStoreException rsne) {}

        return ret;
    }
}

RMSMIDlet.java

package examples.addressbook;
import java.lang.*;
import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import javax.microedition.midlet.*;

/**
 * A simple class that shows various functionality of RMS.
 * The general flow of this MIDlet is:
 *
 *      In the constructor (See RMSMIDlet),
 *      create and populate two record stores, one of personal
 *      contacts, the other with business contacts.
 *      Display the first screen. This screen shows a list
 *      of all RMS stores found in the MIDlet suite's name
 *      space. This screen allows the user to select a
 *      record store and either display pertinent information
 *      about the record store such as size, etc., or to view
 *      the contents of the selected store. When the contents
 *      of a record store are viewed, they are sorted by last
 *      name, although this can be changed by instantiating a
 *      SimpleComparator object with the appropriate
 *      sort order parameter.
 *
 *      Traversal from screen to screen is handled
 *      by RMSMIDlet, commandAction.
 *
 */
public class RMSMIDlet extends MIDlet implements CommandListener {
    private Display myDisplay;  // handle to the display
    private Alert alert;        // used to display errors

    // Our commands to display on every screen.
    private Command CMD_EXIT;
    private Command CMD_DETAILS;
    private Command CMD_OK;
    // Our screens
    private List mainScr;
    private List detailScr;
    private List dataScr;

    // An array of all RMS stores found in this
    // MIDlets name space.
    private String[] recordStoreNames;

    /**
     * Seed data for creating personal contacts RMS store
     */
    private final String personalContacts[] = {
        "John", "Zach", "2225556669",
        "Mark", "Lynn", "5125551212",
        "Joy", "Beth", "2705551234",
        "Abby", "Lynn", "4085558566",
    };

    /**
     * Seed data for creating business contacts RMS store
     */
    private final String businessContacts[] = {
        "Ted", "Alan", "4125552235",
        "Sterling", "Wincle", "9995559111",
        "Deborah", "Elaine", "4445552323",
        "Suzanne", "Melissa"," 5125556064",
        "Frank", "Kenneth", "7775551212",
        "Dwight", "Poe", "1115557234",
        "Laura", "Beth", "2055558888",
        "Lisa", "Dawn", "2705551267",
        "Betty", "June", "5555551556",
        "Yvonne", "Poe", "6665558888",
        "Lizzy", "Loo", "5025557971",
        "John", "Gerald", "3335551256",
    };

    /**
     * Display warning on the screen and revert to main screen
     *
     * A warning string to display
     */
    private void doAlert(String s) {
        alert.setString(s);
        myDisplay.setCurrent(alert, mainScr);
    }

    /**
     * Notify the system we are exiting.
     */
    private void doExit() {
        destroyApp(false);
        notifyDestroyed();
    }

    /**
     * In our simple MIDlet, all screens have the same commands,
     * with the possible exception of the detailScr.
     *
     * Also set up the command listener to call commandAction.
     * See RMSMIDlet#commandAction
     */
    private void addCommonCommands(Screen s,
                                   boolean doDetails) {
        s.addCommand(CMD_OK);
        s.addCommand(CMD_EXIT);
        if (doDetails) {
            s.addCommand(CMD_DETAILS);
        }
        s.setCommandListener(this);
    }

    /**
     * The public constructor. In our constructor, we get
     * a handle to our display and create two record stores.
     * In the event of an error, we display an alert.
     */
    public RMSMIDlet() {
        CMD_EXIT = new Command("Exit", Command.EXIT, 3);
        CMD_DETAILS = new Command("Details", Command.SCREEN, 2);
        CMD_OK = new Command("OK", Command.OK, 1);
        myDisplay = Display.getDisplay(this);
        alert = new Alert("Warning");
        alert.setTimeout(2000);
        CreateAddressBook.createRecordStore("Personal",
                                            personalContacts);
        CreateAddressBook.createRecordStore("Business",
                                            businessContacts);

        // Now, get a list of RMS stores and add their
        // names to the mainScr.
        recordStoreNames = RecordStore.listRecordStores();
        mainScr = new List("Select RMS Store", List.IMPLICIT,
                           recordStoreNames, null);
        addCommonCommands(mainScr, true);
    }

    /**
     * Called by the system to start our MIDlet.
     */
    protected void startApp() {
        myDisplay.setCurrent(mainScr);
    }

    /**
     * Called by the system to pause our MIDlet.
     * No actions required by our MIDLet.
     */
    protected void pauseApp() {}

    /**
     * Called by the system to end our MIDlet.
     * No actions required by our MIDLet.
     */
    protected void destroyApp(boolean unconditional) {}

    /**
     * Generate a screen with a sorted list of the contents
     * of the selected RMS store identified by index.
     * If any errors encountered, display an alert and
     * redisplay the mainScr.
         *
         *
     * index an index into recordStoreNames
     */
    public void genDataScr(int index) {
        SimpleComparator rc;
        RecordEnumeration re;
        RecordStore rs;
        dataScr;
        byte record[];

        try {
            rs = RecordStore.openRecordStore(
                                recordStoreNames[index], false);
        } catch (RecordStoreException e) {
            doAlert("Could not open " + recordStoreNames[index]);
            return;
        }

        // Create an enumeration that sorts by last name
        rc = new SimpleComparator(
                     SimpleComparator.SORT_BY_LAST_NAME);
        try {
            re = rs.enumerateRecords(null, rc, false);
        } catch (RecordStoreNotOpenException e) {
            doAlert("Could not create enumeration: " + e);
            return;
        }

        // Create a screen and append the contents of the
        // selected RMS store.
        dataScr = new List(recordStoreNames[index] + " Data",
                           List.IMPLICIT);
        addCommonCommands(dataScr, false);

        try {
            while (re.hasNextElement()) {
                byte[] b = re.nextRecord();
                dataScr.append(SimpleRecord.getFirstName(b) +
                               " " + SimpleRecord.getLastName(b),
                               null);
            }
        } catch (Exception e) {
            doAlert("Could not build list: " + e);
            dataScr = null;
        } finally {
            try {
                rs.closeRecordStore();
            } catch (RecordStoreException e) {}
        }
    }

    /**
     * Generate a screen that shows some of the details
     * of the selected RMS store.
     *
     * RMS store information displayed:
     * - name
     * - number of records
     * - size, in bytes
     * - available size, in bytes
     * - version number
     *
     * index  an index into recordStoreNames
     */
    public void genDetailScr(int index) {
        RecordStore rs;
        detailScr = null;

        try {
            rs = RecordStore.openRecordStore(
                                        recordStoreNames[index],
                                        false);
        } catch (Exception e) {
            doAlert("Could not open " + recordStoreNames[index]);
            return;
        }

        detailScr = new List(recordStoreNames[index] + " Details",
                             List.IMPLICIT);
        addCommonCommands(detailScr, false);

        try {
            detailScr.append("Name: "  + rs.getName(), null);
            detailScr.append("# recs: " +
                             rs.getNumRecords(), null);
            detailScr.append("Size: " + rs.getSize(), null);
            detailScr.append("Avail: " +
                             rs.getSizeAvailable(),null);
            detailScr.append("Version: " +
                             rs.getVersion(), null);
        } catch (Exception e) {
            detailScr = null;
            doAlert("Failed to retrieve data");
            return;
        } finally {
            try {
                rs.closeRecordStore();
            } catch (RecordStoreException e) {}
        }
    }

    /***
     * Respond to command selections.
     * Commands are:
     * EXIT: if selected, then exit
             (see RMSMIDlet, doExit)
     * OK:   if selected, interpreted in the context of
     *       the current screen.
     *
     * This method implements a state machine that drives
     * the MIDlet from one state (screen) to the next.
     */
    public void commandAction(Command c,
                              Displayable d) {

        // Every screen has an EXIT command.
        // Handle this consistently for all screens.
        if (c == CMD_EXIT) {
            doExit();
            return;
        }

        // Switch based on screen.
        if (d == mainScr) {
            // Main screen: two commands to handle. If
            // OK was selected, then generate the dataScr
            // and make it active. If DETAILS was selected,
            // generate the detailScr and make it active.
            if ((c == List.SELECT_COMMAND) || (c == CMD_OK)) {
                genDataScr(mainScr.getSelectedIndex());
                myDisplay.setCurrent(dataScr);
            } else if (c == CMD_DETAILS) {
                genDetailScr(mainScr.getSelectedIndex());
                myDisplay.setCurrent(detailScr);
            }

        } else if (d == detailScr) {

            // If OK selected, go back to mainScr
            if (c == CMD_OK) {
                myDisplay.setCurrent(mainScr);
            }

        } else if (d == dataScr) {

            // If OK selected, go back to mainScr
            if (c == CMD_OK) {
                myDisplay.setCurrent(mainScr);
            }

        }
    }
}


14.4 New for MIDP 2.0

The most requested feature for RMS in MIDP 2.0 was the ability to share record stores between MIDlet suites. This was addressed by adding an access mode to class RecordStore so that the owner of the RecordStore can allow shared or private access, and can differentiate between read-only or read-write access modes. The MIDlet suite that creates the RecordStore owns it and controls access to it. Other MIDlet suites can open shared record stores by giving the MIDlet suite name and the record store name. This new functionality makes it possible to share persistent data between MIDlet suites.


Chapter 15. MIDP Networking and Serial Communications

MIDP target devices operate on a wide variety of wireless and wired networks with incompatible transport protocols. In addition, wireless networks have less bandwidth, more latency, and less stable connections than wired networks. The MIDP Specification version 2.0 must accommodate these differences and allow for future network technologies. To do so, MIDP uses standard network programming mechanisms and practices and takes advantage of the existing network infrastructure.

MIDP specifies that HTTP and HTTPS are required protocols for all devices. In addition, it defines APIs for optional protocols: datagrams, sockets, secure sockets, and serial communication ports. (See Chapter 16, "Secure Networking" for more information on the secure networking protocols.)


15.1 Characteristics of Wireless Data Networks

The MIDP Specification version 2.0 addresses two types of wireless data networks: circuit-switched data (CSD) and packet-switched data (PSD). A wireless circuit-switched network (also called a session-based network) assigns a user a radio channel, which it dedicates to the connection until the data transfer is done. During the data exchange, the channel cannot be used for anything else. The GSM cellular phone network is a circuit-switched data network.

Data over a circuit-switched network is usually billed on a time basis, like voice transmissions. Using a circuit-switched wireless network for data transfer can be expensive because data rates in today's wireless networks are rather low. In a GSM phone, for example, the data rate is usually about 9.6 kilobits per second (kbps).

The other type of wireless data network is packet-switched. In packet-switched data transmissions, the data exchange is broken up into small packets that usually have a fixed length. Packets from several different data exchanges, each from different users, can be sent in time slots of the same radio channel. The packets are mixed during transmission and reassembled in the correct order by the recipients. Packet-switched data uses the radio spectrum more efficiently than circuit-switched data. In addition, packet-switched data is usually billed by the amount of data sent, so packet-switched networks are generally cheaper for data transfer.

The next-generation wireless-network technologies promise much greater data rates than the networks in widespread use today. The second-and-a-half generation (2.5G) wireless technologies, such as General Packet Radio Service (GPRS), and third-generation (3G) technologies, such Wideband Code Division Multiple Access (WCDMA), are generally packet-switched technologies. For example, the theoretical maximum data transfer rate of GPRS is 171.2 kilobits per second, and third generation wireless networks offer theoretical data rates up to a few megabits per second.


15.2 Network Interface Considerations

MIDP devices must support the HTTP protocol, a rich, widely used protocol that can be implemented relatively easily over a variety of wireless networks. HTTP lets devices take advantage of the extensive server-side infrastructure already in place for wired networks. Furthermore, because no unrequested HTTP packets can arrive at the device, implementing the networking interface is easier.

Supporting the HTTP protocol does not imply that the device must support a particular Internet Protocol (IP). A device can implement HTTP using IP protocols such as TCP/IP, or non-IP protocols such as WAP or i-Mode. If a device uses a non-IP protocol, a computer called a gateway bridges the wireless protocol to and from HTTP servers on the Internet and provides IP-based network facilities such as server name resolution (for example, DNS).

Many wireless networks have evolved to support IP-based protocols, so the MIDP Specification version 2.0 defines the corresponding APIs and behaviors. The new MIDP 2.0 APIs are SocketConnection (Section 15.5, "SocketConnection"), ServerSocketConnection (Section 15.6, "ServerSocketConnection"), and UDPDatagramConnection (Section 15.7, "UDPDatagramConnection"). In addition, the CommConnection API (Section 15.8, "CommConnection") supports serial communications. Support for these protocols is optional, but most networks are expected to support them. They enable MIDlets using the protocols to run consistently across implementations.

Implications for application developers

When designing MIDP applications, it is important to keep in mind that many networking and communications API calls can be time-consuming and can potentially block the application thread. For instance, networking operations such as opening connections or receiving data from a server can cause the application thread to be blocked while waiting for the network activity to be completed.

Application developers should design their applications so that the applications do not invoke any time-consuming network operations in the callback functions that are invoked as a result of user interface actions. For instance, CommandListener functions should not generally invoke networking functions, as listeners require a separate thread to keep the user interface functionality from interfering with the responsiveness of the application. In addition, upon invoking time-consuming networking operations, the application should always display a progress screen, such as Gauge, and include a "Cancel" command to allow the user to escape from potentially indefinitely blocking network activity.


15.3 The HttpConnection Interface

The interface javax.microedition.io.HttpConnection defines the MIDP HTTP API. This interface is unchanged from MIDP 1.0. The interface extends the interface javax.microedition.io.ContentConnection to provide additional fields and methods that parse URLs, set request headers, and parse response headers. (Refer to the documentation of interface ContentConnection on page 69.)

15.3.1 States of an HTTP Connection

An HTTP connection exists in one of three states: setup, connected, or closed.

A connection is in the setup state after it is opened and before the request has been made to the server. The application sets information needed to connect to the server, such as the request parameters and headers. (They must be set before the request is sent.) The methods setRequestMethod and setRequestProperty set the values; the getRequestMethod and the getRequestProperty methods retrieve them.

A connection enters the connected state when the request is sent. This occurs when the application calls a method that requires a response value or closes the output stream, if any. These methods indicate the end of the request.

A connection enters the closed state when the connection is closed. Although none of the methods of the HttpConnection object can be used when the connection is closed, its InputStream or OutputStream might still contain data. The streams may be used until they are closed. The following code fragment shows an input stream being used after its connection has been closed:

// Open the connection and input stream
HttpConnection c = (HttpConnection)Connector.open(...);
InputStream is = c.openInputStream();

...

// Close the connection. Can't call HttpConnection methods
// after this, but InputStream methods are still available.
c.close();
while ((int ch = is.read()) != -1) {
    ...
}
// Close the input stream. Can't call InputStream methods after this
is.close();

15.3.2 Security of HTTP

Access to the HTTP connection may be restricted by device policy. Trusted MIDlet suites request access with the javax.microedition.io.Connector.http permission, as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid URL. If the authorization fails and the MIDlet is not allowed to use the HTTP API, the Connector.open method throws a java.lang.SecurityException.

15.3.3 Establishing a Connection

Applications open HTTP connections with the CLDC method javax.microedition.io.Connector.open. (Refer to Section 5.3.2, "The Generic Connection Framework.") The method takes a single String URL parameter in the URI (Uniform Resource Identifier) form as defined by the IETF standard RFC2396 Uniform Resource Identifiers [reference 5]. Opening the connection might block the application thread until the server responds. The application should make sure this code runs in a thread separate from the user interfaces callbacks. The following code fragment opens a connection to the home page of the Java™ Programming Language.

HttpConnection c =
    (HttpConnection)Connector.open("http://java.sun.com/");

The resulting connection supports the HTTP 1.1 protocol as defined by RFC2616 [reference 9]. The connection is in the setup state.

15.3.4 Parsing URLs

While an HTTP connection is open, a MIDlet can parse the components of its URL. The URL-parsing methods are:

  • getProtocol: returns the protocol component of the URL.

  • getHost: returns the host component of the URL.

  • getPort: returns the port number component of the URL.

  • getFile: returns the file component of the URL.

  • getQuery: returns the query component of the URL (the text after the first question mark (?) character in the URL).

  • getRef: returns the reference component of the URL (the text after the crosshatch (#) character in the URL).

The following example uses these accessor methods:

// Open the Connection
String HTTP_URL =
    "http://localhost:8080/myApp?first=joe?last=cool";
HttpConnection c = (HttpConnection)Connector.open(HTTP_URL);

// Can now use the URL parsing methods
System.out.println("Protocol: " + c.getProtocol());
System.out.println("Host: " + c.getHost());
System.out.println("Port: " + c.getPort());
System.out.println("File: " +  c.getFile());
System.out.println("Query: " + c.getQuery());
System.out.println("Reference: " + c.getRef());

When run, the code prints the following lines:

Protocol: http
Host: localhost
Port: 8080
File: /myApp
Query: first=joe?last=cool
Reference: null

15.3.5 HTTP Request Headers

The HTTP protocol provides a rich set of request headers that allow a MIDlet to negotiate the form, format, language, session, and other attributes of the content posted or retrieved. The protocol also provides response headers.

It is the responsibility of a MIDlet to choose the request headers to use and to process response headers. When a MIDlet communicates with a known service, it needs to handle only a subset of headers. It can omit and ignore the others.

The following methods set the request method and headers. A MIDlet can use them when its connection is in the setup state.

  • setRequestMethod: sets the request method to one of the following POST, GET, or HEAD; if not set, then the default is GET.

  • setRequestProperty: sets the name and value of a request header.

  • getRequestMethod: returns the current request method.

  • getRequestProperty: returns a previously set request property.

Of the request properties that can be set, the User-Agent, Accept-Language, and Authorization properties merit special discussion.

The User-Agent Header

In the HTTP specification, a request header called User-Agent identifies the current client to the server. As specified by RFC2616 [reference 9], the field contains features separated by blanks. A feature consists of a name and optional version number.

The MIDP Specification version 2.0 does not require that a MIDlet set the User-Agent field. A MIDlet can use it, though, to identify its device to the server. The following code fragment sets the User-Agent field to the version numbers of the CLDC and MIDP implementations running on the device:

StringBuffer sb = new StringBuffer(60);

// Add the Configuration to the string that is the User-Agent value
sb.append("Configuration/");
sb.append(System.getProperty("microedition.configuration"));

// For each profile, append it to the User-Agent string
String prof = System.getProperty("microedition.profiles")
int i = 0, j = 0;
while ((j = prof.indexOf(' ', i)) != -1) {
    sb.append(" Profile/");
    sb.append(prof.substring(i, j));
    i = j + 1;
}
sb.append(" Profile/");
sb.append(prof.substring(i));

// Set the User-Agent field
c.setRequestProperty("User-Agent", sb.toString());
The Accept-Language Header

The Accept-Language header requests a document in a particular language. The header can be set with the value of the system property microedition.locale, which identifies the current locale of the device. (See Section 20.2, "System Properties" for more information.) The following code fragment shows the Accept-Language header being set with the microedition.locale value.

String locale = System.getProperty("microedition.locale");
if (locale != null) {
    c.setRequestProperty("Accept-Language", locale);
}
The Authorization Header

The HTTP protocol provides several mechanisms that a client and server can use to to implement a challenge-response authentication scheme [reference 10]. One scheme, the basic authentication scheme, has the client send a userId-password pair to the server in the Authorization header. The server uses the authentication data to give the client access to a protected resource, or realm. The server only handles a request to access a realm if it can validate the user identifier and password the client supplied.

To use a basic authentication scheme, the Authorization header must contain the string Basic, a space, and then the base64 [reference 3] encoding of a string composed of the user-ID, a colon, and password. For example, if a client needed to access a protected resource that requires a user-ID of book and a password of bkpasswd, the MIDlet would send the following header field:

Authorization: Basic Ym9vazpia3Bhc3N3ZA==

where the 'Ym9vazpia3Bhc3N3ZA==' string is the base64 encoding of book:bkpasswd.

The Authorization header can also be used for other authentication schemes. See RFC2617 [reference 10] for more information.

15.3.6 Using an HTTP Connection

After a MIDlet sets the appropriate headers it can use the connection. The connection's action depends on the value (GET, POST, or HEAD) set with the setRequestMethod method.

Using the GET Request Method

The GET method retrieves information. The following code fragment shows the common situation in which an application opens an HttpConnection, checks the connection's status (which sends the request), and then reads data from the connection using the InputStream of the connection.

HttpConnection c;
InputStream is;
try {
    // Open the connection
    c = (HttpConnection)Connector.open("http://java.sun.com/");

    // Get the HTTP response code, which sends the request
    // Only HTTP_OK (200) means that the content is returned
    int status = c.getResponseCode();
    if (status != HttpConnection.HTTP_OK) {
        throw new IOException("Response code not OK");
    } else {
        // Handle other recoverable responses like redirects
    }

    // Open the InputStream and read until end of file
    // (-1) is returned
    is = c.openInputStream();

    int ch;
    while ((ch = is.read()) != -1) {
        // Process the byte from the stream;
    }
} finally {
    // Close the connection and the InputStream
    if (is != null) {
        is.close();
    }
    if (c != null) {
        c.close();
    }
}
Using the POST Request Method

POST requests can send more data and parameters to a server than GET requests. When using a POST request, a MIDlet can provide parameters as part of the URL (as with a GET request). In addition, the MIDlet can write a stream of bytes over the network in order to supply the server with additional data.

The example below shows a POST request. The example opens the connection and sets up the request headers. It then opens an OutputStream and writes additional data or commands into the stream before sending the request to the server.

HttpConnection c;
InputStream is;
OutputStream os;

try {
    // Open the connection
    c = (HttpConnection)Connector.open(url);

    // Make this a POST request
    c.setRequestMethod(HttpConnection.POST);

    // Get the output stream and write a command
    os = c.openOutputStream();
    os.write("LIST games\n".getBytes());
    os.flush();

    // Get the status code, causing the request to be sent
    // Only HTTP_OK (200) means the request was accepted
    status = c.getResponseCode();
    if (status != HttpConnection.HTTP_OK)
        throw new IOException("Response status not OK");
}
Using the HEAD Request Method

The HEAD request method is like the GET request method except the server does not return a message body in the response. All of the information in the HTTP headers is identical. An application usually uses a HEAD request to test whether a URL is valid or modified.

15.3.7 HTTP Response Headers

An HTTP server responds to a request by sending one or more headers that describe the content of the response, such as the type, encoding, length, and so on. The requested content is sent next. The HttpConnection object parses and stores the response headers until the connection is closed. The MIDlet must get any headers it needs from the connection before closing it. It uses the information to interpret the returned content.

The methods that fetch and convert the commonly used fields to the appropriate primitive type are:

  • getResponseCode: returns the value of the response code.

  • getResponseMessage: returns the value of the response message.

  • getEncoding: returns the value of the content-encoding as a string.

  • getType: returns the content-type header field as a string.

  • getLength: returns the content-length header field as a size in bytes.

  • getDate: returns the value of the date header in milliseconds.

  • getExpiration: returns the value of the expires header in milliseconds.

  • getLastModified: returns the value of the last-modified header in milliseconds.

Additional response headers are also available. Methods provide access to the fields by index or name as a String, an integer, or a time in milliseconds. If a header may appear more than once (as Set-Cookie can) a MIDlet must iterate through the response headers using getHeaderFieldKey to identify which headers have multiples. The methods to iterate through and get the values of the fields are:

  • getHeaderField(String name): returns the value of the named header field as a String.

  • getHeaderField(int n): returns the value of the nth header (starting from zero).

  • getHeaderFieldKey(int n): returns the name of the nth header (starting from zero).

  • getHeaderFieldInt(String name, int n): returns the value of the named field converted to an integer.

  • getHeaderFieldDate(String name, long def): returns the value of the named field in milliseconds.

All of the header-related methods catch any exceptions that occur in making the connection and return default values. To avoid missing a network error or incorrectly acting upon it, a MIDlet should call getResponseCode, check the return value, and be prepared to handle any exceptions before getting the response headers.

15.3.8 Closing an HTTP Connection

An application closes an HTTP connection with the javax.microedition.io.Connector.close method. The following example shows a connection being closed.

try {
    c.close();
} catch (IOException e) {
    ...
}


15.4 Sample Code (NetClientMIDlet.java)

The following application, NetClientMIDlet, demonstrates how HTTP can be used to log in to a server, send data, and receive a response.

The MIDlet begins by displaying the instructional screen shown in the top figure. If the user selects OK, the MIDlet sends a POST request that contains a user identifier and password for a basic authentication scheme. It also sends the message Esse quam videri ("To be rather than to seem.")

After sending the message, the MIDlet reads the returned values. A screen full of the values are shown in the next figure: a string identifying itself (such as "NetServer Servlet" as shown in the bottom figure), followed by a date string, the original POST message body, the message body reversed, and a complete list of headers read from the POST request. (The figure only shows the first header.)

The example consists of three classes. The NetClientMIDlet class extends the MIDlet class. It implements the MIDlet life cycle methods and has the device display the screens shown in the figures. The ConnectionManager class opens the HTTP connection to a server, sends the information, and reads the response. The BasicAuth class transforms the user identifier and password into a base64 encoded string.

NetClientMIDlet.java

This class creates the MIDlet's user interface and manages its states. The constructor creates the MIDlet's screens. The startApp method displays the main screen, which is an instructional screen, the first time it is called. If the user selects OK on the main screen, the run method is called. The run method creates a ConnectionManager instance and sets the connection manager's msg field to "Esse quam videri", its user field to book, and its password field to bkpasswd. The run method then has the connection manager handle the request and displays the results that the connection manager returns.

// Package and import declarations
package examples.netclient;
import java.lang.*;
import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

// Example use of the HTTP networking interface. It opens an
// HTTP POST connection to a server and uses it to authenticate
// with an HTTP Basic Authentication scheme and send a string
// to the server. This MIDlet then reads and displays the response.
public class NetClientMIDlet extends MIDlet
    implements CommandListener, Runnable {

    private Display display;    // handle to the display
    private TextBox mainScr;    // main screen
    private Command cmdOK;      // OK command
    private Command cmdExit;    // EXIT command
    private Form progress;      // Progress Form

    // Creates the MIDlet, its main screen, its progress screen,
    // and its commands. It also caches the MIDlet's display.
    public NetClientMIDlet() {
        display = Display.getDisplay(this);
        mainScr = new TextBox("NetClient",
                    "Press OK to connect to network service",
                    1024, TextField.UNEDITABLE);
        cmdOK = new Command("OK", Command.SCREEN, 1);
        cmdExit = new Command("Exit", Command.EXIT, 1);
        mainScr.addCommand(cmdOK);
        mainScr.addCommand(cmdExit);
        mainScr.setCommandListener(this);
        display.setCurrent(mainScr);

        progress = new Form("Progress");
        Gauge g = new Gauge("Waiting...", false, Gauge.INDEFINITE,
                            Gauge.CONTINUOUS_RUNNING );
        progress.append(g);
        progress.addCommand(cmdExit);
        progress.setCommandListener(this);
    }

    // The system calls this method to start the MIDlet.
    protected void startApp() {}

    // The system calls this method to pause the MIDlet.
    // Does nothing: there are no global resources to release.
    protected void pauseApp() {}

    // The system calls this method to exit the MIDlet.
    // Does nothing: there are no global resources to release.
    protected void destroyApp(boolean unconditional) {}

    // Gets and displays data from the server
    public void run() {
        // Create and set parameters to communicate with the server
        ConnectionManager h = new ConnectionManager();
        h.setMsg("Esse quam videri");
        h.setUser("book");
        h.setPassword("bkpasswd");

        // Communicate with the server
        byte[] data = h.Process();
        // Display the result of the communication
        if (data == null || data.length == 0) {
            // Tell user no data was returned
            Alert alert = new Alert("Alert",
                                    "No information available",
                                    null, AlertType.ERROR);
            display.setCurrent(alert, mainScr);
        } else {
            // Create data screen
            TextBox dataScr = new TextBox("Data Screen", "",
                                          1, TextField.UNEDITABLE);
            dataScr.addCommand(cmdOK);
            dataScr.addCommand(cmdExit);
            dataScr.setCommandListener(this);

            dataScr.setMaxSize(data.length);
            dataScr.setString(new String(data));
            display.setCurrent(dataScr);
        }
    }

    // Respond to user commands, invoke the next task
   public void commandAction(Command c, Displayable d) {
        if (c == cmdOK) {
            if (d == mainScr) {
                // Communicate with the server without blocking UI
                display.setCurrent(progress);
                new Thread(this).start();
            } else {
                // Display the main screen
                display.setCurrent(mainScr);
            }
    } else if (c == cmdExit) {
            // Exit the MIDlet
            destroyApp(false);
            notifyDestroyed();
        }
    }
}

ConnectionManager.java

The ConnectionManager class manages the HTTP POST connection. The run method of the NetClientMIDlet class creates an instance of the class, and then calls the process method of the new instance.

The constructor sets the strings for the User-Agent and Accept-Language headers. The process method opens the HTTP connection by calling the open method. The example hard codes the URL of the server in the variable baseurl; the variable refers to a simple Java servlet that accepts HTTP POST connections.

After it opens the connection, the process method sets the HTTP request type to HttpConnection.POST to allow the MIDlet to write data to the server. It then sets the HTTP header fields to the values shown in Table 15.1.

Table 15.1. HTTP header values

Header

Value

User-Agent

The string Profile/MIDP-1.0 Configuration/CLDC-1.0

Accept-Language

The value of the system property microedition.locale or the string en-US if the property is not set

Content-Length

The length of the field msg

Content-Type

The string text/plain

Authorization

The string Basic followed by a space, followed by the base64 encoding of user:password

As the final step in preparing the request, the process method opens the connection's output stream, writes a message, and closes the output stream. At that point the network connection is made, the stored headers are flushed, and the msg field is written to the server.

The connection manager calls the getResponseCode method to see whether the connection was successful. Its subsequent actions depend on the status code. There are three response cases to handle:

  • HttpConnection.HTTP_OK: The connection was opened and the data was written. In this case, the connection manager opens an InputStream and reads the response data from the server.

  • HttpConnection.HTTP_MOVED_TMP, HttpConnection.HTTP_MOVED_PERM, or HttpConnection.HTTP_TEMP_REDIRECT: The server is trying to redirect the request. In this case, the connection manager reads the location header and uses the new URL.

  • The connection was not opened for an unexpected reason; in this case, the connection manager throws an IOException.

package examples.netclient;
import java.lang.*;
import java.util.*;
import java.io.*;
import javax.microedition.io.*;

// Establishes an HTTP POST connection to the server defined by
// baseurl, sends headers and a message, and reads the response.
// It sets the following HTTP headers:
// User-Agent:      CLDC and MIDP version strings
// Accept-Language: microedition.locale or "en-US" if that is null
// Content-Length:  the length of msg
// Content-Type:    text/plain
// Authorization:   "Basic" + the base 64 encoding of user:password
class ConnectionManager {
    private HttpConnection con;
    private InputStream is;
    private OutputStream os;
    private final String baseurl =
        "http://127.0.0.1:8080/Book/netserver";
    private String ua;
    private String locale;
    private String msg;
    private String user;
    private String password;

    // Creates the connection manager and creates the values for the
    // User-Agent and Accept-Language headers.
    ConnectionManager() {
        StringBuffer sb = new StringBuffer(60);
        sb.append("Configuration/");
        sb.append(
            System.getProperty("microedition.configuration"));

        // For each profile, append it to the user agent string
        String prof = System.getProperty("microedition.profiles");
        int i = 0, j = 0;
        while ((j = prof.indexOf(' ', i)) != -1) {
            sb.append(" Profile/");
            sb.append(prof.substring(i, j));
            i = j + 1;
        }
        sb.append(" Profile/");
        sb.append(prof.substring(i));
        ua = sb.toString();

        // Initialize the current locale
        locale = System.getProperty("microedition.locale");
        if (locale == null) {
            locale = "en-US";
        }
    }

    // Processes an HTTP connection request and returns the result
    // in a form that can be displayed for the end user.
    byte[] Process() {
        byte[] data = null;

        try {
            // Open connection, send data, and check response status
            open();

            // Read the response (open would throw an IOException
            // if there were nothing to read.)
            int n = (int)con.getLength();
            if (n > 0) {
                int bytesread = 0;
                data = new byte[n];
                for (int offset = 0; offset < n;
                     offset += bytesread) {
                     bytesread = s.read(data, offset, n-bytesread);
                }
            }
        } catch (IOException ioe) {
            // Close the connection and any open streams
        } finally {
            try {
                if (con != null) {
                    con.close();
                 }
                if (os != null) {
                    os.close();
                 }
                if (is != null) {
                    s.close();
                 }
             } catch (IOException ioe) {
                 return data;
             }
        }
    }

    // Open a connection to the server
    private void open() throws IOException {
        int status = -1;
        String url = baseurl;
        String auth = null;
        is = null;
        os = null;
        con = null;
        // Loop until a connection is made (in case of redirects)
        while (con == null) {
            // Set up the connection values (headers, and so on)
            con = (HttpConnection)Connector.open(url);
            con.setRequestMethod(HttpConnection.POST);
            con.setRequestProperty("User-Agent", ua);
            con.setRequestProperty("Accept-Language", locale);
            con.setRequestProperty("Content-Type", "text/plain");
            con.setRequestProperty("Accept", "text/plain");
            if (user != null && password != null) {
                con.setRequestProperty("Authorization",
                    "Basic " + BasicAuth.encode(user, password));
            }
            // Write the message to the output stream. Opening
            // the output stream might flush the headers
            os = con.openOutputStream();
            os.write(msg.getBytes());
            os.close();
            os = null;

            // check status code (if the headers and message
            // were not flushed before, they will be sent now.)
            status = con.getResponseCode();
            switch (status) {
                case HttpConnection.HTTP_OK:
                // Success! Calling method will read the response
                break;
                 case HttpConnection.HTTP_TEMP_REDIRECT:
                 case HttpConnection.HTTP_MOVED_TEMP:
                 case HttpConnection.HTTP_MOVED_PERM:
                     // Redirect: get the new location
                     url = con.getHeaderField("location");
                     con.close();
                     con = null;
                     break;
                 default:
                     // Error: throw an I/O exception
                     con.close();
                     throw new IOException("Response status not OK:"
                         + status);
            }
        }
        // Open input stream so the caller can read the response
        is = con.openInputStream();
    }

    // Access methods for the fields of the class

    // Set the message to send to the server
    void setMsg(String s) {
        msg = s;
    }
    // Set the user name to use to authenticate to server
    void setUser(String s) {
            user = s;
    }
    // Set the password to use to authenticate to server
    void setPassword(String s) {
        password = s;
    }
}

BasicAuth.java

The BasicAuth class is a utility class; it cannot be instantiated. It has a static method, encode, that creates and returns a string that holds the base64 encoding of its two string arguments. Note that the encode method provides only a subset of the functionality required by RFC2045 [reference 3]. It does not handle strings longer than 76 characters, line breaks, and so forth.

package examples.netclient;

// Encodes a user name and password in the base64 format that
// HTTP Basic Authorization requires. This is a utility class: it
// provides a static method and cannot be instantiated.
class BasicAuth {
    // make sure no one can instantiate this class
    private BasicAuth() {}

    // Conversion table
    private static byte[] cvtTable = {
        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E',
        (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J',
        (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O',
        (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T',
        (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y',
        (byte)'Z',
        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e',
        (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j',
        (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o',
        (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t',
        (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y',
        (byte)'z',
        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
        (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
        (byte)'+', (byte)'/'
    };
    // Encodes a name-password pair appropriate to
    // use in an HTTP header for Basic Authentication.
    //    name     the user's name
    //    passwd   the user's password
    //    returns  String    the base64 encoded name:password
    static String encode(String name, String passwd) {
        byte input[] = (name + ":" + passwd).getBytes();
        byte[] output = new byte[((input.length / 3) + 1) * 4];
        int ridx = 0;
        int chunk = 0;

    // Loop through input with 3-byte stride. For each chunk of
    // 3-bytes, create a 24-bit value, then extract four 6-bit
    // indices. Use these indices to extract the base64 encoding
    // for this 6-bit character
        for (int i = 0; i < input.length; i += 3) {
            int left = input.length - i;
            // We have at least three bytes of data left
            if (left > 2) {
                chunk = (input[i] << 16) |
                        (input[i + 1] << 8) | input[i + 2];
                output[ridx++] = cvtTable[(chunk&0xFC0000)>>18];
                output[ridx++] = cvtTable[(chunk&0x3F000) >>12];
                output[ridx++] = cvtTable[(chunk&0xFC0)   >> 6];
                output[ridx++] = cvtTable[(chunk&0x3F)];
            } else if (left == 2) {
                // Down to 2 bytes; pad with 1 '='
                chunk = (input[i] << 16) | (input[i + 1] << 8);
                output[ridx++] = cvtTable[(chunk&0xFC0000)>>18];
                output[ridx++] = cvtTable[(chunk&0x3F000) >>12];
                output[ridx++] = cvtTable[(chunk&0xFC0)   >> 6];
                output[ridx++] = '=';
            } else {
                // Down to 1 byte; pad with 2 '='
                chunk = input[i] << 16;
                output[ridx++] = cvtTable[(chunk&0xFC0000)>>18];
                output[ridx++] = cvtTable[(chunk&0x3F000) >>12];
                output[ridx++] = '=';
                output[ridx++] = '=';
           }
       }
       return new String(output);
   }
}


15.5 SocketConnection

The SocketConnection interface extends interface javax.microedition.io.StreamConnection to define the API to TCP/IP or similar socket streams. (Refer to the documentation of interface StreamConnection on page 69.)

Applications that need to accept connections from other applications must use ServerSocketConnection instead. See Section 15.6, "ServerSocketConnection" for more information.

An application opens a socket on a target host by calling the Connector.open method. The application must provide a URI string that starts with 'socket://' and is followed by a host name and port number separated by a colon. For example, 'socket://host.com:79' has the correct syntax to open a socket connection on the host.com system at port 79.

In the string the MIDlet can specify the host as a fully qualified host name or IPv4 number. Note that RFC1900 [reference 2] recommends the use of host names rather than IP numbers. Using the host name means the MIDlet can still make the connection, even if the host's IP number is reassigned. For example, 'socket://host.com:79' is preferred to 'socket://183.206.241.133:79'. If the connection string uses incorrect syntax, Connector.open throws an IllegalArgumentException exception.

The Connector.open method returns a SocketConnection instance. It has methods that enable the MIDlet to get the local and remote addresses and the local and remote port numbers, and to control socket options.

15.5.1 Getting the Local Address and Port Number

An application can get the local host address and port number for an open connection. (This information is needed primarily by applications that use a ServerSocketConnection to allow clients to make inbound connections to a system-assigned port. See Section 15.6, "ServerSocketConnection" for more information.) The getLocalAddress method returns the local IP number to which the socket is bound. Calling System.getProperty("microedition.hostname") returns the host name of the device, if it is available. The getLocalPort method returns the local port to which this socket is bound.

If an application sends address and port information to a remote application so that it can connect to the device, the application should try to send the host name of the device. IP addresses can be dynamically assigned, so a remote application with only an IP address will not be able to make contact if the device IP number changes. If a host name is available, sending it would help the remote application be more robust.

15.5.2 Getting the Remote Host Address and Port

An application can get the remote host address and port number for an open connection. The getAddress method returns the remote host (as either a host name or an IP address) to which the socket is bound. The getPort method returns the remote port to which this socket is bound. The methods get their return values from the string passed to Connector.open.

15.5.3 Getting and Setting Socket Options

An application can control some low-level socket options to optimize interactions with the network. The socket options inform the low-level networking code about the application's intended usage patterns. The options are listed in Table 15.2.

The setSocketOption method sets the value for a socket option for the connection. The getSocketOption method returns the value for a socket option for the connection or –1 if the value is not available. Both methods throw an IllegalArgumentException if the value is not valid (for example, if the value is negative) or the option identifier is not valid.

For example, if a MIDlet calls the setSocketOption method to assign buffer sizes, the device can use this as a hint about the sizes to set the underlying network I/O buffers. The system might adjust the buffer sizes to account for better throughput available from Maximum Transmission Unit (MTU) and Maximum Segment Size (MSS) data available from current network information.

Table 15.2. Socket options

Option

Description

DELAY

Small-buffer writing delay. Setting this option to zero disables the TCP Nagle algorithm for small buffer operations. Setting it to a non-zero value enables it.

KEEPALIVE

Keep-alive feature. Setting this option to zero disables the keep-alive feature. Setting it to a non-zero value enables it.

LINGER

Number of seconds to wait before closing a connection with pending data output. Setting the linger time to zero disables the linger wait interval.

RCVBUF

Size of the receiving buffer, in bytes.

SNDBUF

Size of the sending buffer, in bytes.

15.5.4 Closing Streams

Every stream connection has an associated Connection object, InputStream and OutputStream. These objects have their own close methods and, on systems that support duplex communication over the socket connection, closing the input or output stream shuts down only that side of the connection. For example, closing the InputStream does not stop the OutputStream from sending data.

Both the input and output stream must be closed before the connection is completely closed. Conversely, the application will receive an IOException if it tries to use a closed input stream, output streams, or socket connection.

15.5.5 Security of SocketConnection

Access to a socket connection is restricted to prevent unauthorized transmission or reception of data. MIDlet suites needing to use sockets must request the javax.microedition.io.Connector.socket permission for Trusted MIDlet suites as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid socket connection string. If the authorization fails and the MIDlet is not allowed to use the socket API, the Connector.open method throws a java.lang.SecurityException. The device might also check the MIDlet's permission when the MIDlet calls the openInputStream, openDataInputStream, openOutputStream, or openDataOutputStream methods.

15.5.6 Example

The following example shows the use of a SocketConnection to send and receive text from the echo port of a remote host. Refer to previous examples for the complete handling of exceptions and closing of streams and the connection.

// Open the socket and its associated streams. Set the linger time
SocketConnection sc =
    (SocketConnection)Connector.open("socket://host.com:7");
sc.setSocketOption(SocketConnection.LINGER, 5);
DataInputStream is  = sc.openDataInputStream();
DataOutputStream os = sc.openDataOutputStream();

// Write to and read from the remote echo port
os.writeUTF("Hello World\n");
os.flush();
String result = is.readUTF();
// Close the connection and its streams
is.close();
os.close();
sc.close();


15.6 ServerSocketConnection

The ServerSocketConnection interface defines the server socket stream API. A server socket connection is not a socket or stream connection; it only establishes that the application is accepting incoming connections. The ServerSocketConnection interface extends the interface javax.microedition.io.StreamConnectionNotifier, which listens for incoming connections. (Refer to the documentation of interface StreamConnectionNotifier on page 69.)

An application establishes a server socket connection by calling the Connector.open method. The application must supply a URI string with the host omitted. For example, "socket://:7" defines an inbound server socket on port 7 (the echo port). If the application also omits the port number, the device dynamically selects an available port. For example, "socket://" defines an inbound server socket on a port allocated by the system. If the connection string is invalid, the Connector.open method throws an IllegalArgumentException.

When the application needs to connect to the socket (for example, to handle an incoming request) it invokes the acceptAndOpen method of the server socket connection. The acceptAndOpen method returns a SocketConnection instance. See Section 15.5, "SocketConnection," for information on the returned instance. As with other blocking network calls, the application should invoke these methods only in a thread designated for the purpose; use of the user interface callbacks to invoke these methods will block the user interface.

15.6.1 Getting the Local Address and Port Number

An application can get the address and port on which the device will accept connections. The getLocalAddress method returns the IP address of the device. The getLocalPort method returns the assigned port number. See Section 15.5.1, "Getting the Local Address and Port Number" for more information, but remember that the values returned from the ServerSocketConnection versions of the methods are not the address and port of an active SocketConnection.

15.6.2 Security of ServerSocketConnection

Access to a server socket connection is restricted to prevent unauthorized transmission or reception of data. MIDlet suites needing to use server sockets must request the javax.microedition.io.Connector.serversocket permission for Trusted MIDlet suites as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device tries to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid server socket connection string. If the authorization fails and the MIDlet is not allowed to use the server socket API, the Connector.open method throws a java.lang.SecurityException. The device also checks the MIDlet's permission when the MIDlet calls the acceptAndOpen method and might check when the MIDlet calls the openInputStream, openDataInputStream, openOutputStream, or openDataOutputStream methods.

15.6.3 Example

The following example shows a ServerSocketConnection providing an echo service. (It does not, however, use the standard echo port, which is port 7.) The example also omits the exception handling needed in a complete program.

// Create the server listening socket for port 1234
ServerSocketConnection scn =
    (ServerSocketConnection) Connector.open("socket://:1234");

// Wait for a connection
SocketConnection sc = (SocketConnection) scn.acceptAndOpen();

// When a connection is made, set the socket's options
sc.setSocketOption(DELAY, 0);
sc.setSocketOption(LINGER, 0);
sc.setSocketOption(KEEPALIVE, 0);
sc.setSocketOption(RCVBUF, 128);
sc.setSocketOption(SNDBUF, 128);

// Get the input and output streams of the connection
DataInputStream is = sc.openDataInputStream();
DataOutputStream os = sc.openDataOutputStream();

// Read the input data and echo it back to the sender
String result = is.readUTF();
os.writeUTF(result);
// Close the server socket, its socket, and the socket's streams
is.close();
os.close();
sc.close();
scn.close();


15.7 UDPDatagramConnection

The UDPDatagramConnection interface extends the interface java.microedition.- io.DatagramConnection to define a UDP datagram connection. (Refer to the documentation of interface DatagramConnection on page 69.) The UDP datagram protocol is defined by the IETF standard RFC768 [reference 1]. The protocol is message-oriented; delivery and duplicate protection are not guaranteed. Applications use UDP datagram connections to exchange messages with minimal overhead, but if ordered reliable delivery of streams of data is required, a SocketConnection is a better choice.

An application opens a UDP datagram connection by calling the Connector.open method. The application must provide a URI string that starts with "datagram://" and is followed by a host name and port number separated by a colon. If the string has neither the host nor port fields, the device allocates an available port. If the connection string is invalid, an IllegalArgumentException is thrown.

15.7.1 Getting the Local Address and Port Number

An application can get the local host address and port number for an open connection. (This information is needed primarily for applications that use UDPDatagramConnections to allow clients to send datagrams to a dynamically assigned port.) The getLocalAddress method returns the local IP number to which the socket is bound. Calling the method System.getProperty("microedition.hostname") returns the host name of the device, if it is available. The getLocalPort method returns the local port to which this socket is bound.

If an application sends address and port information to a remote application so that it can connect to the device, the application should try to send the host name of the device. IP addresses can be dynamically assigned, so a remote application with only an IP address will not be able to make contact if the device IP number changes. If a host name is available, sending it would help the remote application be more robust.

15.7.2 Datagrams

The UDPDatagramConnection interface inherits methods to create, send, and receive datagrams from the interface javax.microedition.io.DatagramConnection. Once created, a datagram can be used and reused for reading or writing. A Datagram consists of an address and a data buffer. The address is a URL string in the same syntax as described for the method Connector.open. If the datagram will be sent, the application uses the Datagram.setAddress method to assign a destination address. (The address must include both the host and port.) If the Datagram was received, the address contains the source address.

The data buffer is a byte array with an offset and a length. An application can access the byte array either directly or indirectly through the datagram's DataInputStream for reading and DataOutputStream for writing. The datagram's getOffset and setOffset methods are the accessor methods for the offset of the first byte of data. The getLength and setLength methods are the accessor methods for the number of bytes of data in the datagram. The data buffer, offset, and length must be set before the Datagram is sent. Before receiving a Datagram, the buffer, offset, and length must also be set to indicate the bytes available to store the incoming message.

The datagram also has a reset method that is used to initialize the internal state used for reading and writing. Mixing reads, writes, and direct access to the data buffer is not recommended because the interactions between them are complex.

The number of bytes that the UDPDatagramConnection can handle for each send and receive may be limited. The getNominalLength method returns the normal size that the transport can handle in a single packet. The getMaximumLength method returns the upper limit on the size of a datagram. Some transports fragment a large datagram into smaller pieces for transport and reassemble them at the destination.

15.7.3 Closing Connections

An application closes a UDP datagram connection with the javax.microedition.io.Connector.close method. The UDPDatagramConnection methods throw an IOException if an application attempts to call the methods after the connection has been closed.

15.7.4 Security of UDPDatagramConnection

Access to datagrams is restricted to prevent unauthorized transmission or reception of data. MIDlet suites needing to use datagrams must request the javax.microedition.io.Connector.datagram permission for Trusted MIDlet suites as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid datagram connection string. If the authorization fails and the MIDlet is not allowed to use the UDP datagram connection API, the Connector.open method throws a java.lang.SecurityException. The device might also check the MIDlet's permission when the MIDlet calls the receive or send methods.

15.7.5 Example

Applications can use datagrams to asynchronously send and receive information. The following example uses a thread to receive datagrams of the maximum possible size on a known port and process the messages it receives. When it receives a zero length datagram it closes the connection and terminates.

public void run() {
    UDPDatagramConnection c = null;
    Datagram dgram;
    try {
        // Open the UDP Datagram Connection
        c = (UDPDatagramConnection)
                Connector.open("datagram://:4444");
        int max = c.getMaximumLength();

        // Create a new datagram with a maximum-sized data buffer
        dgram = c.newDatagram(max);
        byte[] buf = dgram.getData();

        // Read in and process datagrams (stop at an empty datagram)
        while (true) {
            dgram.setLength(max);
            c.receive(dgram);
            int len = dgram.getLength();
            if (len == 0) {
                // All done: close and return
                break;
        } else {
            // Process the data
            process(buf, len);
        }
    }
} catch (IOException ex) {
     // handle the exception
} finally {
    // Close the connection
    try {
        c.close();
    } catch (IOException ex) {
    }
}


15.8 CommConnection

The CommConnection interface defines an API for a logical serial port connection. The CommConnection extends the StreamConnection interface, through which bytes are transferred using input and output streams. The underlying operating system defines the logical serial ports that can be used. Such a port does not need to correspond to a physical RS-232 serial port. For instance, IrDA IRCOMM ports are commonly configured as logical serial ports within the device.

An application opens a serial port by calling the Connector.open method. The application must provide a URI string that begins with "comm:" followed by a port identifier, followed optionally by a semicolon and a semicolon-separated list of parameter-value pairs. The name of a parameter is separated from its value with an equals sign (=). Spaces are not allowed in the string. For example, "comm:COM0;baudrate=19200" is a valid string.

The port identifier is a logical device name defined by the device. Port identifiers will probably be device-specific, so applications should use them with care. (See Section 15.8.3, "Recommended Convention for Naming Ports.") Applications can get a comma-separated list of valid port identifiers for a particular device and operating system by calling the System.getProperty method with the key microedition.commports.

Any additional parameters must be separated by a semicolon. If a particular optional parameter is not applicable to a particular port, the device is permitted to ignore it. Legal parameters are listed in Table 15.3. If the application supplies an illegal or unrecognized parameter, the Connector.open method throws an IllegalArgumentException. If the device supports a parameter value, it must be honored. If the device does not support a parameter value, the Connector.open method throws a java.io.IOException. If an option duplicates a previous option, the last value overrides the previous value.

Table 15.3. CommConnection parameters for opening serial connections

Parameter

Default

Description

baudrate

platform dependent

Speed of the port in bits per second (such as 9600 or 19200)

bitsperchar

8

Number of bits per character (7 or 8)

stopbits

1

Number of stop bits per char (1 or 2)

parity

none

Parity (even, odd, or none)

blocking

on

Whether to wait for a full buffer. (on, which means wait, or off, which means do not wait)

autocts

on

Whether to wait for the CTS line to be on before writing (on, which means wait, or off, which means do not wait)

autorts

on

Whether to turn on the RTS line when the input buffer is not full (on, which means turn on the RTS line when the input buffer is not full, or off, which means the RTS line is always on)

Only one application may be connected to a particular serial port at a given time. The Connector.open method throws a java.io.IOException if an application tries to open the serial port when the connection is already open.

15.8.1 Getting and Setting the Serial Port Speed

The application may need to know or set the baud rate (speed) of the serial port to communicate with an external device. There are two ways to set the baud rate. The application can set it in the Connector.open method by putting the optional parameter baudrate into the method's URI string argument. The application can also set the baud rate after the connection is open with the setBaudRate method. If the application does not set a value, the baud rate defaults to a device-specific default value. If the application requests a baud rate that the device does not support, the system may substitute a valid baud rate. The application determines the actual baud rate of the connection by calling the getBaudRate method.

15.8.2 Security for CommConnection

Access to serial ports is restricted to prevent unauthorized transmission or reception of data. MIDlet suites needing to use serial ports must request the javax.microedition.io.Connector.comm permission for Trusted MIDlet suites as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid serial port connection string. If the authorization fails and the MIDlet is not allowed to use the serial port connection API, the Connector.open method throws a java.lang.SecurityException. The device might also check the MIDlet's permission when the MIDlet calls the methods openInputStream, openDataInputStream, openOutputStream, or openDataOutputStream methods.

15.8.3 Recommended Convention for Naming Ports

A logical port name can use any combination of alphanumeric characters except a semicolon. Although logical port names can be defined to match a platform's naming conventions, implementations of the virtual machine should use the following convention: port names should contain a text abbreviation indicating port capabilities followed by a sequential number for the port. The following device name types should be used:

  • COM#: where COM is for RS-232 ports and # is a number assigned to the port.

  • IR#: where IR is for IrDA IRCOMM ports and # is a number assigned to the port.

This naming scheme allows the API users to generally determine the type of port that they would like to use. For instance, if an application wants to beam a piece of data, the application could look for IR# ports for opening the connection. The alternative is a trial-and-error approach with all available ports.

15.8.4 Examples

This section provides two examples of serial port access using the CommConnection interface. The first example shows how a CommConnection would be used to access a simple program that echoes the characters it receives. The second example shows how to discover the serial ports available on the device and select the first available serial port.

The following example shows a program that echoes characters through a CommConnection.

// Open the CommConnection and its streams
CommConnection cc =
    (CommConnection)Connector.open("comm:com0;baudrate=19200");
int baudrate = cc.getBaudRate();
InputStream is = cc.openInputStream();
OutputStream os = cc.openOutputStream();

// Write characters and read them back in
int ch = 0;
while (ch != 'Z') {
    os.write(ch);
    ch = is.read();
    ch++;
}

// Close the connection and its streams
is.close();
os.close();
cc.close();

The following example shows how to discover the available serial ports on the device and select the first available serial port.

// Get the comma-separated list of ports
String port1;
String ports = System.getProperty("microedition.commports");

int comma = ports.indexOf(',');
if (comma > 0) {
    // Parse the first port from the available ports list
    port1 = ports.substring(0, comma);
} else {
    // Only one serial port available
    port1 = ports;
}


15.9 New for MIDP 2.0

MIDP Specification version 2.0 introduced several new network and communication APIs. The SocketConnection API can be used for reliable connections with servers without the overhead of HTTP. The ServerSocketConnection API allows a device to handle incoming connections. The UDPDatagramConnection API provides for low overhead but unreliable delivery of datagrams and has certain device and network caveats. The CommConnection API defines operations for accessing serial ports on a device if they are available.

It must be kept in mind that there are many mobile devices that do not provide support for sockets, and therefore the availability of the networking protocols will vary from one device to another. The networks provided by different network operators may also have limitations in the support of specific networking protocols. Also, access to some of the protocols may be prohibited because of the security policies of the device or the network. Close cooperation with the device manufacturer and the network operators' developer programs will be helpful in understanding how to use these APIs and how they may be enabled in particular networks.


Chapter 16. Secure Networking

Many mobile applications, especially those intended for mobile commerce, need secure transport protocols in order to ensure the integrity and confidentiality of transactions that are initiated by the applications. Secure protocols such as Secure Sockets Layer (SSL) and Transport Layer Security (TLS) have been in common use on the Internet for some time. The MIDP Specification version 2.0 now brings secure networking protocols also to the developers of J2ME applications.

The MIDP Specification version 2.0 defines two secure networking interfaces: HttpsConnection and SecureConnection. The HttpsConnection interface extends the interface HttpConnection, and the SecureConnection interface extends the interface SocketConnection. When a MIDlet opens an HTTPS connection or a secure socket connection, the client device and the server establish a secure link by negotiating the secure protocol and cipher suite, and by exchanging credentials.

Because the client and server components of mobile applications are usually designed and deployed together to satisfy a particular business need, the server-side infrastructure can define the confidentiality and integrity requirements. The client-side implementations needs to verify only that the client is communicating with the correct site and protocols.

Secure networking protocols supported by MIDP 2.0 include SSL and TLS as well as the Wireless Application Protocol (WAP) secure protocol WTLS. Each protocol places requirements on certificates used for secure networking, as described in Section 16.4, "MIDP X.509 Certificate Profile."


16.1 Checking the Security Properties of a Connection

The device and the server negotiate the secure connection parameters based on mutually agreeable secure suites. After the connection has been established, the application can retrieve a SecurityInfo object and verify the integrity and server credentials of a negotiated connection. A MIDlet using an HTTPS or secure connection gets the object by calling the getSecurityInfo method on the open connection. If the MIDlet's connection is not secure enough, it can report an error and close the connection.

The application can use the SecurityInfo object to get the protocol name, protocol version, cipher suite, and certificate for a secure network connection. Table 16.1 lists the names and versions of the protocols available by calling the getProtocolName and getProtocolVersion methods of the SecurityInfo interface.

Table 16.1. Secure protocols and version numbers

Secure Protocol

Protocol Name

Version

SSL V3

"SSL"

"3.0"

TSL 1.0

"TLS"

"3.1"

WTLS (WAP-199)

"WTLS"

"1"

WAP TLS Profile and Tunneling Specification

"TLS"

"3.1"

The getCipherSuite method of the SecurityInfo interface returns the name of the cipher suite used for the connection. The name is usually one of the standard ciphers listed in the CipherSuite column of the CipherSuite definitions table in Appendix C of RFC 2246 [reference 4]. Non-TLS implementations should select the cipher suite name according to the key exchange, cipher, and hash combination used to establish the connection. This will ensure that equivalent cipher suites have the same name regardless of protocol. If the getCipherSuite method returns a non-null name that is not in Appendix C of RFC 2246 [reference 4], the cipher suite's contents are specific to the device and server.

16.1.1 Server Certificate

An application calls the getServerCertificate method of the SecurityInfo object to get the server's certificate. A Certificate object contains a subject, issuer, type, version, serial number, signing algorithm, dates of valid use, and serial number.

The subject is the entity that vouches for the identity of the server; the issuer is the distinguished name of the entity that vouches for the identity of the subject. An application gets the subject from the getSubject method of the Certificate object and the issuer from the getIssuer method. The getIssuer method never returns null. The subject and issuer strings are formatted using the rules for the printable representation for X.509 distinguished names given in Section 16.1.2, "Printable Representation for X.509 Distinguished Names."

The type and version of the certificate are returned by the getType and getVersion methods of the Certificate object. The format of the version number depends on the specific type and specification, but is never null. For X.509 certificates, the value returned is X.509, and the version, per RFC 2459 [reference 7], is 2.

The application gets the name of the algorithm used to sign the certificate from the getSigAlgName method of the Certificate object. The algorithm names returned should be one of the labels defined in RFC 2459, Section 7.2 [reference 7]. For example, md5WithRSAEncryption is a valid return value.

The getSerialNumber method returns the printable form of the serial number of this Certificate or null if there is no serial number. A binary serial number should be formatted as a string using the binary-printable representation: a colon-separated list of bytes in which each byte is represented by two hex digits (capital letters for A–F). For example, "0C:56:FA:80" is in binary-printable representation.

Each X.509 certificate is valid for only a specified period of time. The getNotBefore method of the Certificate object returns the time before which the certificate may not be used. The time is the milliseconds before which the certificate is not valid; the value zero means the certificate does not have its validity restricted by time. The getNotAfter method is the time after which the certificate is not valid. The time is the milliseconds after which the certificate is not valid (the expiration date); Long.MAX_VALUE is returned if the certificate does not have its validity restricted by time. Both times must be positive.

16.1.2 Printable Representation for X.509 Distinguished Names

The distinguished name (DN) for an X.509 certificate is a semicolon-separated list of attributes. Each attribute has an object ID (represented by a label or a binary-printable representation) and a value. Table 16.2 lists common attributes and their labels. For example, "C=US;O=Any Company, Inc.;CN=www.anycompany.com" is a DN.

Table 16.2. Labels for X.500 distinguished name attributes

Object ID

Label

Binary-Printable Representation

id-at-commonName

CN

55:04:03

id-at-surname

SN

55:04:04

id-at-countryName

C

55:04:06

id-at-localityName

L

55:04:07

id-at-stateOrProvinceName

ST

55:04:08

id-at-streetAddress

STREET

55:04:09

id-at-organizationName

O

55:04:0A

id-at-organizationUnitName

OU

55:04:0B

emailAddress

EmailAddress

2A:86:48:86:F7:0D:01:09:01

For string comparison purposes, the following rules define a strict printable representation that can be used for literal comparisons of distinguished names.

  1. Attributes are separated by a semicolon.

  2. There is no added white space around separators.

  3. The attributes are in the same order as in the certificate; attributes are not reordered.

  4. If an object-ID is in Table 16.2, the label from the table will be substituted for the object-ID. Otherwise, the object-ID is formatted as a string using the binary-printable representation described in Section 16.1.1, "Server Certificate."

  5. Each object ID or label within an attribute will be separated from its associated value by an equals sign (=), even if the value is empty.

Any non-string value is formatted as a string using the binary-printable representation described in Section 16.1.1, "Server Certificate."


16.2 HttpsConnection

HTTPS is the secure version of the HTTP protocol [reference 9]. (See Section 15.3, "The HttpConnection Interface," for more information.) The MIDP Specification version 2.0 requires a secure HTTP connection to comply with one or more of the following specifications:

  • HTTP over TLS: documented in both RFC 2818 [reference 11] and TLS Protocol Version 1.0 as specified in RFC 2246 [reference 4].

  • SSL V3: specified in The SSL Protocol Version 3.0 [reference 12].

  • WTLS: specified in the Wireless Application Protocol Wireless Transport Layer Security document WAP-199 [reference 13].

  • WAP™ TLS Profile and Tunneling Specification WAP-219-TLS [reference 14].

The HttpsConnection interface extends the interface HttpConnection to define MIDP HTTPS API. The HttpsConnection interface has the same methods and behaviors as its superinterface, and adds information about the security parameters of the connection. An application accesses an HttpsConnection by calling the Connector.open method. The application must supply a URI with the scheme "https:". RFC 2818 [reference 11] defines the scheme.

A secure link must be established so the request headers can be sent securely. The secure link may be established as early as in the invocation of the Connector.open method. It may also be established when the application opens the connection's input or output stream or calls methods that cause a transition to the connected state. (See Section 15.3, "The HttpConnection Interface," for information on these methods.) Any method that can cause a secure link to be established may experience security-related failures; such methods throw a CertificateException to indicate these failures.

16.2.1 Security of HttpsConnection

Access to the secure HTTP connection may be restricted to prevent unauthorized transmission or reception of data. Trusted MIDlet suites needing to use HTTPS must request the javax.microedition.io.Connector.https permission as described in "Trusted MIDlet Suite Security Model" on page 308.

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid HTTPS connection string. If the authorization fails and the MIDlet is not allowed to use the HTTPS API, the Connector.open method throws a SecurityException. The device might also check the MIDlet's permission when the MIDlet calls the openInputStream, openDataInputStream, openOutputStream, and openDataOutputStream methods.

16.2.2 Example

The following example shows a MIDlet using an HttpsConnection. The example opens the connection, reads the server's response, and closes the connection and its input stream. The example does not set any request headers. It uses the default request method of GET, does not request that the response be in any particular language, and so on. See Section 15.3.5, "HTTP Request Headers," for more information.

void getViaHttpsConnection(String url)
        throws CertificateException, IOException {
    HttpsConnection c = null;
    InputStream is = null;
    try {
        // Open the secure connection using the URL provided
        c = (HttpsConnection)Connector.open(url);

        // Get the InputStream. This opens the connection if it was
        // not already done by Connector.open(). Opening the
        // connection does the SSL handshake and reads the
        // HTTP response headers. The implementation stores the
        // headers until the application requests them.
        is = c.openDataInputStream();

        // Always check the response code
        if (c.getResponseCode() == HttpConnection.HTTP_OK) {
            // Get the length of the data
            int len = (int)c.getLength();
            if (len > 0) {
                // If have the length, read it all in at once
                byte[] data = new byte[len];
                int actual = is.readFully(data);
                ...
            } else {
                // If don't have the length, read char by char
                int ch;
                while ((ch = is.read()) != -1) {
                    ...
                }
            }
        } else {
            // Handle error response codes
            // ...
        }
    } finally {
        // Close the connection and its input stream.
        if (is != null) is.close();
        if (c != null) c.close();
    }
}


16.3 SecureConnection

The SecureConnection interface defines the API for a secure socket connection. Interface SecureConnection, like its superinterface SocketConnection, allows a client to connect to a server and has the added benefit of a secure transport. The MIDP Specification version 2.0 requires that a SecureConnection comply with one or more of the following specifications:

  • TLS Protocol Version 1.0: specified in RFC 2246 [reference 4].

  • SSL V3: specified in The SSL Protocol Version 3.0 [reference 12].

  • WAP(TM) TLS Profile and Tunneling Specification: specified in WAP-219-TLS-20010411-a [reference 14].

There is no support for the complementary server-side secure connection in the MIDP Specification version 2.0.

An application opens a secure connection on a target host by calling the Connector.open method. The application must supply a GCF string with the scheme ssl, a host, and a port number. The host may be a fully qualified host name or an IPv4 number. For example, "ssl://host.com:79" defines a target socket on the host.com system at port 79. RFC 1900 [reference 2] recommends the use of names rather than IP numbers for best results in the event of IP number reassignment. Some networks and devices, however, may support only IP addresses since DNS name resolution may introduce additional latency and costs.

Unlike an HTTPS connection, the Connector.open method always opens the secure connection. If the secure connection cannot be established due to errors related to certificates, the Connector.open method throws a CertificateException.

16.3.1 Security of SecureConnection

Access to secure connections may be restricted to prevent unauthorized transmission or reception of data. Trusted MIDlet suites needing to use an SSL/TLS connection must request the javax.microedition.io.Connector.ssl permission as described in Section 18.3, "Trusted MIDlet Suite Security Model."

The device may try to authorize the MIDlet when the MIDlet calls the Connector.open method with a valid connection string. If the authorization fails and the MIDlet is not allowed to use the secure socket API, the Connector.open method throws a SecurityException. The device might also check the MIDlet's permission when the MIDlet calls the openInputStream, openDataInputStream, openOutputStream, and openDataOutputStream methods.

16.3.2 Example

The following example shows how a SecureConnection would be used to access a program at a remote location that echoes back the characters sent to it.

// Open the connection, check its protocol, and set its options
SecureConnection sc =
    (SecureConnection)Connector.open("ssl://host.com:79");
SecurityInfo info = sc.getSecurityInfo();
boolean isTLS = (info.getProtocolName().equals("TLS"));
sc.setSocketOption(SocketConnection.LINGER, 5);

// Open the connection's streams
InputStream is  = sc.openInputStream();
OutputStream os = sc.openOutputStream();

// Write to the output stream and read from the input stream
os.write("Hello World\n".getBytes());
int ch = 0;
while (ch != -1) {
    ch = is.read();
}

// Close the connection and its streams
is.close();
os.close();
sc.close();


16.4 MIDP X.509 Certificate Profile

MIDP 2.0 devices are expected use standard Internet and wireless protocols and techniques for their transport and security. The protocols and techniques are based on the following Internet standards for public key cryptography:

  • WAP Certificate Profile Specification WAP-211-WAPCert-20010522-a [reference 15] (WAPCert).

    Devices must conform to all mandatory requirements in WAPCert, Appendix C, and should conform to all of its optional requirements except:

    • WAPCert Section 6.2, User Certificates for Authentication.

    • WAPCert Section 6.3, User Certificates for Digital Signatures.

  • RFC 2437 – PKCS #1 RSA Encryption Version 2.0 [reference 6].

  • RFC 2459 – Internet X.509 Public Key Infrastructure [reference 7].

    MIDP 2.0 implementations must support X.509 Certificates and are permitted to support other certificate formats. RFC 2459 [reference 7] contains sections that are not relevant to a MIDP 2.0 implementation, however. The WAP Certificate Profile does not mention these functions. Implementations should exclude:

    • Requirements from Paragraphs 4 of Section 4.2 – Standard Certificate Extensions. A MIDP 2.0 implementation does not need to recognize extensions that must or may be critical, including certificate policies, name constraints, and policy constraints.

    • Section 6.2 Extending Path Validation. Support for Policy Certificate Authority or policy attributes is not required.

16.4.1 Certificate Extensions

A MIDP implementation must consider a version 1 X.509 certificate equivalent to a version 3 certificate with no extensions.

A MIDP 2.0 device must recognize key usage (see RFC 2459 [reference 7] section 4.2.1.3) and basic constraints (see RFC 2459 [reference 7] section 4.2.1.10). It must be able to process certificates with unknown distinguished name attributes and unknown non-critical certificate extensions. It must also recognize the serialNumber attribute defined by WAPCert [reference 15] in distinguished names for Issuer and Subject.

Although a MIDP 2.0 device may not recognize a certificate's authority and subject key identifier extensions (see RFC 2459 [reference 7] sections 4.2.1.1 and 4.2.1.2), it must support certificate authorities that sign certificates using the same distinguished name using multiple public keys.

16.4.2 Certificate Size

A MIDP 2.0 device must be able to process certificates that are not self-signed root certificate authority (CA) certificates of sizes up to at least 1500 bytes.

16.4.3 Algorithm Support

A MIDP 2.0 device must support the RSA signature algorithm with the SHA-1 hash function, sha1WithRSAEncryption, as defined by PKCS #1. Devices that support these algorithms must be capable of verifying signatures made with RSA keys of lengths up to and including 2048 bits.

A MIDP 2.0 device should support both the md2WithRSAEncryption signature algorithms and the md5WithRSAEncryption signature algorithm as defined in RFC 2437 [reference 6]. A MIDP 2.0 device that supports these algorithms must be capable of verifying signatures made with RSA keys of lengths up to and including 2048 bits.

16.4.4 Certificate Processing for HTTPS

A MIDP 2.0 device must recognize the extended key usage extension defined in RFC 2818 [reference 11] if it is present and marked critical. When the extension is present, the device must verify that the extension contains the id-kp-serverAuth object identifier (see RFC 2459 [reference 7] section 4.2.1.13).

SSL and TLS allow the web server to include the redundant root certificate (a self-signed root CA certificate) in the server certificate message. Web servers should not include it in a certificate chain. The device must ignore it if it is a version 1 certificate (as it will most likely be.)


16.5 New for MIDP 2.0

The secure networking functionality described in this chapter is new in MIDP 2.0. The secure networking operations ensure the integrity and privacy of communications using standard secure network protocols. Interface HttpsConnection provides the application developer with the familiar popular network programming protocol HTTPS that integrates easily with the existing network servers and services. The SecureConnection interface extends the flexibility of sockets to the network infrastructure built on the reliable and robust SSL and TLS protocols. Both secure connection types make it easy to write robust and secure network applications.


Chapter 17. Event-Driven Application Launch

The MIDP Specification version 2.0 defines an option to automatically launch a MIDlet when a notification is received. Notifications can be network- or alarm-based. Network notifications, also known as push notifications, can occur when the device receives an incoming network connection for one of its MIDlets. Alarm-based notifications can occur at a time set by a MIDlet.

Automatic launching is not a required device feature. Devices can support both types of notifications, only one type, or neither.

Notifications can cause MIDlets to be launched without direct user intervention; users could be unaware of the activity. For example, if a device launches a MIDlet at a preset time, the user may not be present or paying attention.

A number of security concerns arise from the potential to launch applications without direct user intervention. Security permissions and policy provide safeguards, however. They ensure that MIDlets can perform only activities allowed by the user. (MIDlets, whether launched automatically or at the request of the user, are always subject to the security policy of the device and any permissions the user has granted. See Section 18.3, "Trusted MIDlet Suite Security Model," for more information.) For example, a user can require the device to ask permission before automatically launching a MIDlet.


17.1 Alarm-Based MIDlet Launch

It can often be useful for a MIDlet to be launched at a preset time to provide information to the user in a timely fashion. For example, a MIDlet that sells movie tickets might set an alarm to warn the ticket-holding user about the impending start time of the movie.

To use alarm-based notification, a MIDlet calls the PushRegistry.registerAlarm method. The MIDlet must supply the name of the MIDlet to launch (it must be a MIDlet in the same MIDlet suite) and a launch time. The named MIDlet must have been registered in the JAD file or the JAR manifest with a MIDlet-n attribute. Providing a launch time of zero removes any alarm.

The push registry supports one alarm per MIDlet. If a registration occurs for a MIDlet that already has an alarm set, the new registration is used. The PushRegistry.registerAlarm method returns the old registration time in milliseconds since January 1, 1970, 00:00:00 GMT. Note that the time returned could be in the past. It returns zero for the MIDlet's first alarm registration.

Errors may occur during alarm registration. If the runtime system does not support alarm-based application launch, the registerAlarm method throws a ConnectionNotFoundException. If the MIDlet class name provided is null or is not in a MIDlet-n attribute in the MIDlet suite's JAR manifest or JAD file, the registerAlarm method throws a ClassNotFoundException. If the MIDlet does not have permission to register an alarm, the registerAlarm method throws a SecurityException. (See Section 17.5, "Security of the Push Registry," for more information.)

A device could be unable to launch the MIDlet for the alarm. For example, a MIDlet cannot be launched if the device is off at the wake-up time. Similarly, the MIDlet cannot be launched if it is running at the wake-up time. As a result, MIDlets should be written to check the current time against the scheduled wake-up time. They can use class java.util.TimerTask to manage time-based events while they are running. (See Section 20.1, "Timer Support," for more information.)

As a general rule, do not use the alarm to periodically launch a MIDlet to check for new information. Polling is an inefficient use of phone and network resources. It can run down the battery if it activates the device too often and can incur extra network-usage costs, while providing little or no value to the consumer. Instead, use push notification: have the network service send messages to the MIDlet when new information should be presented to the user.

If push notification cannot be used (for example, if the device does not support it), MIDlets that use alarm-based notification should be written to collapse or compress any duplicate events for MIDlets in the suite. This will help to avoid the usability problems associated with starting the MIDlet too frequently.


17.2 Network-Based MIDlet Launch

Devices can use protocols from the Generic Connection Framework (GCF) for their push functionality. (For more information, refer to Chapter 15, "MIDP Networking and Serial Communications.") Launching a MIDlet when a network connection is received is an efficient mechanism to alert users to time-critical information.

Not all protocols are appropriate for use as push connections. Even if a device supports a protocol for inbound connections, the device is not required to use that protocol in its push mechanism. For example, a device might support server socket connections in a MIDlet, but might not support launching a MIDlet in response to receiving a server socket connection.

The three tasks that enable a MIDlet to be started to handle a push notification are registration, listening, and processing of the connection. During the registration phase, the system is given the expected network connection, the MIDlet to run, and a source-address filter. Listening is done by the Application Management Software (AMS). (See Section 19.2, "MIDP System Software," for more information.) The AMS listens for the registered connections associated with MIDlets that are not running. Processing occurs when a registered connection is made: the AMS will run the corresponding MIDlet, and the MIDlet then assumes control of its connections. The steps for registration, listening, and processing are described in more detail below.

MIDlets use the methods of the javax.microedition.io.PushRegistry class to find and open connections. It uses the normal GCF classes to read, write, and close the connection.

When the MIDlet suite is active it is responsible for handling incoming connections. When the MIDlet suite is destroyed, AMS resumes listening for registered connections.

17.2.1 Registering a MIDlet to Be Launched

MIDlet suites must register for push notifications. They can register either statically or dynamically. Static registration is done by adding attributes to the application descriptor, the JAR manifest, or both. It is called static registration because it uses information that is present at installation time. Static registrations remain valid until the MIDlet suite is removed from the device. Dynamic registration is done with the methods of the PushRegistry class. It is called dynamic registration because MIDlets can enable and disable push notifications as needed. They can also modify registrations as needed.

If a MIDlet requires a particular connection in order to function correctly and will not need to change that connection while the MIDlet is on the device, the application developer should use static registration. Two MIDlet suites on a device cannot use the same connection. If two MIDlet suites have a push connection in common, they cannot be on the device at the same time and still function correctly. The device checks for connection conflicts at installation. If all the static push declarations can be fulfilled, then installation proceeds. If not, the user is notified that there are conflicts, and the MIDlet suite is not installed. (Refer to Chapter 19, "MIDlet Deployment," for connection-conflict errors.) The end-user typically uninstalls one MIDlet in order to successfully install the other.

If a MIDlet can be flexible in its push connections, the application developer should use dynamic registration. That is, dynamic registration is for MIDlets that can use (but do not require) a connection, require a connection for only a short period of time, do not need a well-known endpoint, or might have to change the connection during their lifetime. For example, consider a MIDlet that exchanges data with a server application using a private protocol and can allow the device to allocate a port. The MIDlet could open a connection without specifying a port number, causing the device to allocate an available port. Using the information in the open connection (such as the allocated port), the MIDlet would dynamically register the connection. The MIDlet would also send the connection information to the server application. The MIDlet and server application can then use this connection until the MIDlet unregisters or changes it.

17.2.2 Mechanics of Static Push Registration

An application developer declares a static push registration with the MIDlet-Push-n attribute. The attribute can be in either the MIDlet suite's JAD file or JAR manifest. During installation, the device registers the MIDlet to accept those connections. Each push registration entry consists of a colon-separated attribute-value pair. The attribute is to the left of the colon (:); the value is the comma-separated list to the right:

MIDlet-Push-n: ConnectionURL, MIDletClassName, Filter

  • MIDlet-Push-n: attribute name. Multiple push registrations can be provided in a MIDlet suite. The numeric value for n starts from 1 and must use consecutive ordinal numbers for additional entries. The first missing entry terminates the list. Any additional entries are ignored. (Note that the n value of this attribute does not correspond to the n value of the MIDlet-n attribute. MIDlet-Push-1 does not have to declare a push connection for the MIDlet-1.)

  • ConnectionURL: connection string used in the Connector.open method.

  • MIDletClassName: MIDlet responsible for the connection. The MIDlet class name must correspond to a MIDlet class name in a MIDlet-n attribute. If the named MIDlet appears more than once in the suite, the first matching entry is used. The device uses this information when it displays messages to the user regarding the applications. For example, it displays messages when it has detected push connections or when the user has granted or revoked permissions.

  • Filter: restriction on which senders are valid for launching the requested MIDlet. The syntax and semantics of the Filter field depend on the addressing format used for the protocol. However, every filter can use the wildcard characters "*" and "?". The semantics of those wildcard characters are:

    • *: matches any string, including an empty string. When the Filter value is only this character, connections will be accepted from any sender.

    • ?: matches any single character.

    The MIDP Specification version 2.0 defines the syntax for datagram and socket inbound connections. The Filter for these push attributes must contain a numeric IP address in the same IPv4 and IPv6 formats as their respective URLs. (An IPv6 address includes the square brackets, as in the URL.) It is possible to use wild cards in the IP addresses. For example, 129.70.40.* allows subnet resolution. The port number is not part of the filter.

    When other specifications define push semantics for additional connection types, they must define the expected format for the connection URL string and the expected syntax for the filter field.

The following example shows two entries. One would reserve a stream socket at port 79 and the other a datagram connection at port 50000. (Port numbers are maintained by IANA and cover well-known, user-registered, and dynamic port numbers. See IANA Port Number Registry.)

MIDlet-Push-1: socket://:79, com.sun.example.SampleChat, *
MIDlet-Push-2: datagram://:50000, com.sun.example.SampleChat, *

Static push registrations can cause errors during installation. Conditions that cause installation failure are syntax errors in the push attributes, declaring a connection endpoint that another MIDlet has already reserved, declaring a protocol that the device does not support for push, and referencing a MIDlet class name that is not listed in the MIDlet-n attributes of the MIDlet suite.

A conflict-free installation reserves the requested connections for the exclusive use of the MIDlets in the MIDlet suite. If another application tries to open one of the connections, the attempt will fail with an IOException. In contrast, if a MIDlet in the suite tries to open one of the connections, the call will succeed unless the suite already has the connection open.

17.2.3 Mechanics of Dynamic Push Registration

The PushRegistry.registerConnection method registers a dynamic connection with Application Management Software (AMS). Once registered, the dynamic connection acts just like a statically registered connection. The arguments for the dynamic connection registration are the same as the Push-MIDlet-n attribute used for static registrations: the MIDlet must provide the connection string, the MIDlet to launch, and the filter string. The connection string includes the scheme, host, and port number as appropriate. The connection string can also include optional parameters, separated with semicolons. The MIDlet to launch must be listed in one of the MIDlet suite's MIDlet-n attributes. The filter argument indicates which senders' addresses are allowed to launch the MIDlet. See Section 17.2.2, "Mechanics of Static Push Registration," for more information.

Several kinds of errors can occur during dynamic registration. The device throws an IllegalArgumentException if the connection or filter arguments are null, a ClassNotFoundException if the MIDlet argument is null or names a class that cannot be found in the MIDlet suite, a ConnectionNotFoundException if the runtime system does not support push notification for the requested connection protocol, and an IOException if the connection is already registered or if there are insufficient resources to handle the registration request. The device throws a SecurityException if the MIDlet does not have permission to register a push connection. See Section 17.5, "Security of the Push Registry," for more detail.

The listConnections method gets a MIDlet suite's registered connections; it returns an array of strings, one for each connection. If the method is called with an argument true, the array contains only the connections that have input available; if the argument is false, the array contains all of the MIDlet suite's connections. Each connection string can be used with the getMIDlet and getFilter methods to return the other fields from the push registration. The getMIDlet and getFilter methods return null if the connection was not registered by the current MIDlet suite or if the connection argument was null.

The unregisterConnection method removes dynamic registrations. An application developer calls the method with the same connection string used for the registration. The unregisterConnection method returns true if the removal was successful and false if the connection was not registered or if the connection argument was null. It throws a SecurityException if the connection was registered by another MIDlet suite. If the user deletes the application from the device, its dynamically registered push connections are unregistered automatically.


17.3 Listening and Launching

The Application Management Software (AMS) listens for registered connections and manages the launch of and transition to the appropriate MIDlet. It and the other software on the device provide a seamless integration of native and MIDP applications. The AMS handles the interactions among incoming connections, interrupting the user, starting and stopping applications, and handing off connections to MIDlets. It also enforces the device's security policy and constraints.

For example, if a native application is running when a notification arrives, the AMS must interrupt it. It must give the user control over the interruption (for example, user settings determine whether the interruption is to launch the new MIDlet or to get permission to launch it) and any transition to the MIDlet that responds to the network event. To make the transition, the AMS stops or pauses the running application. It and the other software on the device must work together to make the consumer experience smooth and natural.

The AMS would do similar things if a MIDlet was running when a notification arrives. It would call either the pauseApp method or the destroyApp method to change to the MIDlet that responds to the connection. The MIDlet life cycle defines the duties of the interrupted MIDlet. (Refer to "MIDlet States" on page 82.)

The implementation handles incoming connections in a way that allows them to be held and passed on to the MIDlet when it is started. The requirements for buffering of connections and messages are protocol-specific. There is a general requirement, though, that if a device buffers data, it must provide the buffered information to the MIDlet. The device should supply any buffered data when the launched MIDlet opens the related connection.

When a device supports datagram connections for push notification, it must buffer at least the datagram that caused the startup of the MIDlet. It must also guarantee that when it starts a MIDlet in response to the incoming datagram, the buffered data will be available to the MIDlet when the MIDlet opens the UDPDatagramConnection.

The requirement for devices that support socket connections for push notification is different. The device must guarantee that when it starts a MIDlet in response to an incoming socket connection, the MIDlet can accept the connection by opening the ServerSocketConnection, provided that the connection has not timed out.


17.4 Handling Connections after Launch

The MIDlet is responsible for handling incoming connections once it has been started. When a MIDlet associated with a push connection starts, it should first check why it was started. That is, it should get the list of available connections with input available. (See Section 17.2.3, "Mechanics of Dynamic Push Registration," for information on the listConnections method.) If there are such connections, the MIDlet can assume it was started to handle them.

The AMS holds onto the incoming connections until the MIDlet opens them. (This is known as handing off the connections to the MIDlet.) The MIDlet opens a connection by passing a connection string returned by the listConnections method directly to the Connector.open method.

To prevent data loss, a MIDlet is responsible for all I/O operations on the connection from the time it calls the Connector.open method until it closes the connection. Application developers should avoid closing the connection too early. If the connection is closed but the MIDlet is still running, neither the AMS nor the application will be listening for push notifications. Inbound data could be lost if the application closes the connection before all data has been received.

Application developers should also use a separate thread to perform input and output (I/O) operations and avoid blocking (and possibly deadlocking against) interactive user operations.

A push application should behave in a predictable manner when handling asynchronous data it obtains through the push mechanism. A well-behaved application should inform the user that data has been processed. While it is possible to write applications that do not use any user visible interfaces, launching an application that only performs a background function could be a confusing user experience.


17.5 Security of the Push Registry

The PushRegistry class is protected using the security framework and permissions. A MIDlet suite must have the javax.microedition.io.PushRegistry permission to register an alarm based launch and to statically or dynamically register for network notifications. Push registry permissions are also used to determine whether the user needs to be prompted before launching a MIDlet suite in response to a network or alarm-based notification. The security framework defines the general behavior for user permissions with the interaction modes of oneshot, session, and blanket. Their behavior is specialized for the PushRegistry and AMS, as described in the following list:

  • Oneshot: prompt the user before launching a MIDlet suite in response to a network or alarm-based notification, and for each push registry request (such as registering an alarm or connection).

  • Session: prompt the user before launching a MIDlet suite in response to a network or alarm-based notification, or before the first push registry request (such as registering an alarm or connection) after each launch. The user is not prompted on subsequent uses of the push registry by the MIDlet.

  • Blanket: prompt the user once when the MIDlet is being installed, before the first time the MIDlet suite is launched in response to a network or alarm-based notification, and before it uses the push registry.

In addition to needing permission to use the push registry, the MIDlet must also have permission to use server protocols. That is, the push mechanism uses protocols in which the device is acting as the server; it can accept connections from other entities on the network. To use the push mechanisms and accept connections, the MIDlet suite needs permission to use the protocols that it will use when it acts as a server. For example, a chat program that can be started in response to a socket connection notification would need to have the javax.microedition.io.Connector.serversocket permission. The chat program might use the following attributes in the manifest to request the permissions and static registrations it requires:

[View full width]

MIDlet-Push-1: socket://:79, com.sun.example.SampleChat, *
MIDlet-Permissions: javax.microedition.io.PushRegistry, javax.microedition.io.Connector.
  serversocket


17.6 Sample Usage Scenarios

This section provides two examples of MIDlets that are launched in response to a network notification. The first example is a Chat application that uses a well-known port for communication. The second example is a Ping application that dynamically allocates a port the first time it is started.

17.6.1 Sample Chat Application

The Chat application uses push to receive a message on a well-known port. In order to concentrate on the push functionality, it does not show any corresponding MIDlet that would enable the user to reply to the message.

Note

This sample is appropriate for bursts of datagrams because it loops on the connection, processing received messages.

The JAD file for the Chat application's MIDlet suite includes a static push connection registration shown in boldface. It also includes an indication that this MIDlet requires permission to use a datagram connection for inbound push messages. The following example code shows the JAD file:

[View full width]

MIDlet-Name: SunNetwork - Chat Demo
MIDlet-Version: 1.0
MIDlet-Vendor: Sun Microsystems, Inc.
MIDlet-Description: Network demonstration programs for MIDP
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-1: InstantMessage, /icons/Chat.png, example.chat.SampleChat
MIDlet-Push-1: datagram://:79, example.chat.SampleChat, *
MIDlet-Permissions: javax.microedition.io.PushRegistry, javax.microedition.io.Connector.
  datagramreceiver

The following example code shows the Chat MIDlet. The startApp method launches a thread to handle the incoming data. (An inner class implements the Runnable interface.) Using a separate thread to handle network I/O is the recommended practice. It avoids conflicts between blocking I/O operations and user-interaction events. The thread receives messages until the MIDlet is destroyed.

public class SampleChat extends MIDlet {
    // Current inbound message connection
    DatagramConnection conn;

    // Flag to terminate the message reading thread
    boolean done_reading;

    public void startApp() {
        // List of active connections
        String connections[];

        // Check to see if this session was started due to
        // inbound connection notification
        connections = PushRegistry.listConnections(true);

        // Start an inbound message thread for available
        // inbound messages for the statically configured
        // connection in the application descriptor
        for (int i=0; i < connections.length; i++) {
            Thread t = new Thread(
                new MessageHandler(connections[i]));
            t.start();
        }
        ...
    }

    // Stop reading inbound messages and release the push
    // connection to the AMS listener
    public void destroyApp(boolean conditional) {
        done_reading = true;
        if (conn != null)
            conn.close();
        // Optionally, notify network service that we're
        // done with the current session
        ...
    }

    // Optionally, notify network service
    public void pauseApp() {
        ...
    }

    // Inner class to handle inbound messages on separate thread
    class MessageHandler implements Runnable {
        String connUrl ;
    MessageHandler(String url) {
        connUrl = url;
    }

    // Fetch messages in a blocking receive loop
    public void run() {
        try {
        // Get a connection handle for inbound messages
        // and a buffer to hold the inbound message.
        DatagramConnection conn = (DatagramConnection)
        Connector.open(connUrl);
        Datagram data = conn.newDatagram(
                            conn.getMaximumLength());

        // Read the inbound messages
        while (!done_reading) {
            conn.receive(data);
            ...
        }
    } catch (IOException ioe) {
        ...
    }
}

17.6.2 Sample Ping Application

The Ping application uses push to receive a a datagram and echo it back to the sender. Pings are often used to check whether a network entity is operational.

In this sample, the JAD file associated with the Ping application's MIDlet suite includes an entry (shown in boldface) indicating that the application will need permission to use the datagram connection for inbound push messages. It does not statically register for push notifications, however. The following example code shows the JAD file:

MIDlet-Name: SunNetwork - Demos
MIDlet-Version: 1.0
MIDlet-Vendor: Sun Microsystems, Inc.
MIDlet-Description: Network demonstration programs for MIDP
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-1: JustCallMe, /icons/Ping.png, example.ping.SamplePingMe
MIDlet-Permissions: javax.microedition.io.PushRegistry,
    javax.microedition.io.Connector.datagramreceiver

The following example code shows the Ping MIDlet. The first time it is run, the MIDlet opens a connection and allows the device to assign it an available port. It uses the open connection during the first session to dynamically register the connection with the push registry and to send the connection to the network entity that might ping the device. The MIDlet can reopen the connection in subsequent sessions in response to a inbound connection notification.

public class SamplePingMe extends MIDlet {
    // Name of the current application for push registration.
    String myName = "example.chat.SamplePingMe";
    // List of registered push connections.
    String connections[];
    // Inbound datagram connection
    UDPDatagramConnection dconn;

    public SamplePingMe() {

        // Check to see if the ping connection has been registered.
        // This is a dynamic connection allocated on first-time
        // execution of this MIDlet.
        connections = PushRegistry.listConnections(false);

        if (connections.length == 0) {
            // Request a dynamic port for out-of-band notices.
            // (Omitting the port number has the system allocate
            //  an available port number.)
            try {
                dconn = (UDPDatagramConnection)
                        Connector.open("datagram://");
                String dport =
                    "datagram://:"  + dconn.getLocalPort();

                // Register the port so the MIDlet will wake up,
                // if messages are posted after the MIDlet exits.
                PushRegistry.registerConnection(dport,myName,"*");

                // Post my datagram address to the network
                ...

        } catch (IOException ioe) {
            ...
        } catch (ClassNotFoundException cnfe) {
            ...
        }
    }
}

public void startApp() {
    // Open the connection if it's not already open
    if (dconn == null) {
        // This is not the first time this is run, because the
        // dconn has not been opened by the constructor

        // Check whether the startup has been due to an incoming
        // datagram
        connections = PushRegistry.listConnections(true);

        if (connections.length > 0) {
            // Open the pending datagram that can be received
            dconn = (UDPDatagramConnection)
                Connector.open(connections[0]);

            // Read the datagram
            Datagram d = dconn.newDatagram(
                dconn.getMaximumLength());
            dconn.receive(d);
        } else {
            // There are no pending datagrams, but open
            // the connection for later use
            connections = PushRegistry.listConnections(false);
            if (connections.length > 0) {
                dconn = (UDPDatagramConnection)
                    Connector.open(connections[0]);
            }
        }
    }
}

public void destroyApp(boolean unconditional) {
    // Close the connection before exiting
    if (dconn != null){
        dconn.close();
        dconn = null;
    }
}


17.7 New for MIDP 2.0

Event-driven application launch is a new feature in MIDP 2.0. This feature makes it possible to create applications that can be launched at a preset time or that can respond to events generated by network services.

The ability to define applications that will be launched on a specific network protocol event enables the creation of new kinds of services that can monitor information in the network and can notify a MIDlet suite automatically when the information changes.

The event-driven launch of MIDlets is subject to the security policy of a device, and this feature can be enabled and disabled at the discretion of the user.


Chapter 18. Security for MIDlet Suites

Security in mobile devices presents many interesting and significant challenges. Mobile devices must enable users to take advantage of the applications and services provided on the Internet while still protecting them and their data.

Many parties are interested in the security of mobile devices. Network operators have a strong interest in ensuring the integrity of the data that is sent over their networks so they can provide friendly, useful, lucrative, and reliable services to their customers. Mobile device manufacturers want to create usable, useful devices that provide a compelling experience for consumers. Software developers want to tap into the large and vibrant consumer market to sell games, entertainment, and productivity applications. Consumers want a device that is simple, fun, convenient, and easy to use.

Consumers do not want to be inconvenienced, and they are generally discouraged by the presence of security mechanisms that make the devices more difficult to operate. The big challenge is to keep consumer confidence and convenience in balance. If the consumers do not believe that they can use mobile devices easily, safely, and reliably to access services, they will not use them.

To be confident users of a device, consumers need to know their responsibilities and be aware of the limits on their liabilities. They need to be confident that they are using reliable technology that will not fail or compromise their privacy or security. They need to know that the companies they deal with have confidence in the device and network, and that the transactions that they initiate are safe. They need to have confidence in knowing that their personal information will not be used in unanticipated ways. They need to know when their use of the device is costing them money. These opportunities and constraints come together in the MIDP 2.0 security model.

The MIDP Specification version 2.0 extends the sandbox security model used by MIDP 1.0. It introduces a security model that can safeguard the functions of the device that can expose the user to risk, such as the risk of incurring costs associated with wireless network use or the risk to personal privacy. The MIDP 2.0 security model is also extensible to optional APIs, such as SMS.

The MIDP 2.0 security model tries to reconcile the competing goals of security and usability. Security concerns usually require frequent checking and rechecking that an action is allowed. Improving the usability of applications usually means reducing the number of steps and choices the user needs to make. Often the users first get annoyed and then habituated to repetitious prompts, and become accustomed to responding without really reading or making a conscious choice each time. This reduces or eliminates the effectiveness of security mechanisms that ask the user to confirm each and every access of protected functions.

The MIDP 2.0 security model enables the device to enforce security policy based both on the authentication of the MIDlet suite (verification that it is genuine and has not been tampered with) and on the user choices. The device uses authentication information to define which permissions are allowed and which are delegated to the user. Only when the access permissions are delegated to the user must the implementation protect the resource by requiring an explicit confirmation from the user. This can reduce the number of prompts a user might receive, improving the effectiveness of the security mechanism.


18.1 Assumptions

The following assumptions contributed to the design of the security mechanism and ensured ample flexibility in its implementation:

  • MIDlets do not need to be aware of the security policy except for security exceptions that may occur when using APIs.

  • A MIDlet suite is subject to a single protection domain and its permissible actions. (See Section 18.3.3, "Protection Domain," for an explanation of protection domains.)

  • The internal representation of protection domains and permissions is implementation specific. (See Section 18.3.1, "Permissions," for an explanation of permissions.)

  • The user interface for presenting configuration settings and the results of authentication attempts to the user is implementation-dependent and outside the scope of the MIDP Specification version 2.0.

  • The device must protect its security policy and its information on protection domains so that they are safe from viewing or modification except by authorized parties.

  • If the security policy for a device is static and disallows use of some functions of the security framework, then the implementation of unused and inaccessible security functions may be removed.

  • Security policy allows an implementation to restrict access but must not be used to avoid implementing security-sensitive functionality. For example, unimplemented protocols under the Generic Connection framework must throw a ConnectionNotFoundException, not a security-related exception.


18.2 Sandbox for Untrusted MIDlet Suites

The MIDP Specification version 1.0 constrained MIDlet suites to operate in a sandbox that prevented access to sensitive APIs and functions of the device. This model was useful for many applications, and is included and formalized in the MIDP Specification version 2.0.

A MIDlet suite compliant with MIDP 1.0 must be able to run on a MIDP 2.0 device as an untrusted MIDlet suite. An untrusted MIDlet suite is a MIDlet suite for which the origin and the integrity of the JAR cannot be reliably determined by the device. Untrusted MIDlet suites execute in a restricted environment where access to the protected APIs or functions is either not allowed or allowed only with explicit user permission. The restricted environment is the untrusted domain.

The untrusted domain must allow, with explicit confirmation by the user, access to the protected APIs and functions in Table 18.1. Other restricted APIs on the device may be available to untrusted MIDlet suites depending on the security policy of the device.

Table 18.1. APIs for which untrusted MIDlet suites require confirmation

API

Protocol

javax.microedition.io.HttpConnection

HTTP

javax.microedition.io.HttpsConnection

HTTPS


18.3 Trusted MIDlet Suite Security Model

Today, many functions are provided by applications built into the device. Trust in the applications comes from trust in the device manufacturer and network operator who are clearly identified.

Consumers also need to know and trust downloadable applications and their sources. The MIDP Specification version 2.0 introduces the concept of trusted MIDlet suites, which provides a level of authentication that allows the users to have such confidence. A trusted MIDlet suite is one for which the source, authenticity, and integrity of the JAR can be reliably determined by the device.

The procedure for determining whether a MIDlet suite is trusted is device-specific. Some devices might trust only MIDlet suites obtained from certain servers. Other devices might support only untrusted MIDlet suites. It is also possible for a device to authenticate MIDlet suites with the same strong security mechanisms that web sites rely on everyday: the Public Key Infrastructure (PKI). See Section 18.5, "Establishing Trust for MIDlet Suites by Using X.509 PKI," for more information.

Once the device trusts the MIDlet suite, it can grant the MIDlets in the suite permission to use protected functions. Determining whether to grant a requested permission is known as authorization.

18.3.1 Permissions

Devices use permissions to protect access to APIs or functions that require authorization before being invoked. The permissions described in this section refer only to those APIs and functions that need security protection. They do not apply to APIs that do not require authorization and can be accessed by both trusted and untrusted MIDlet suites. (Section 18.4, "APIs That Are Not Security Sensitive," covers the non-security-sensitive APIs.)

A MIDP implementation typically gives trusted applications more access to security-sensitive APIs than untrusted MIDlets. To ensure that access is granted appropriately, the implementation checks permissions prior to each invocation of a protected function. MIDlet suites must have their permission request granted before the implementation provides the function.

Table 18.2 summarizes the permissions that apply to the restricted APIs.

Table 18.2. Summary of Permissions defined by the MIDP Specification

Permission

Restricted API

javax.microedition.io.
  Connector.http

javax.microedition.io.
  HttpConnection

javax.microedition.io.
  Connector.https

javax.microedition.io.
  HttpsConnection

javax.microedition.io.
  Connector.datagram

javax.microedition.io.
  UDPDatagramConnection

javax.microedition.io.
  Connector.datagramreceiver

javax.microedition.io.
  UDPDatagramConnection

javax.microedition.io.
  Connector.socket

javax.microedition.io.
  SocketConnection

javax.microedition.io.
  Connector.serversocket

javax.microedition.io.
  ServerSocketConnection

javax.microedition.io.
  Connector.ssl

javax.microedition.io.
  SecureConnection

javax.microedition.io.
  Connector.comm

javax.microedition.io.
  CommConnection

javax.microedition.io.
  PushRegistry

javax.microedition.io.
  PushRegistry

Permission Names

The names of permissions are case-sensitive and have a hierarchical organization similar to package names in the Java™ programming language. The names of the permissions for an API must begin with the package name of the API. If the permission is for functionality provided by a specific class in the package, then the permission must begin with both the package and class names. Any additional modifiers may be appended after a period (.) separator.

The set of valid characters for permission names is the same as the set for package and class names. Permission names should use the same conventions for capitalization as package names.

For example, javax.microedition.io.Connector.datagram is the permission that protects the use of datagram functionality. As the permission name indicates, the class javax.microedition.io.Connector (a static factory class for creating new connection objects) provides the datagram connection. The class also provides connection objects for other protocols, hence the period followed by the modifier datagram in the permission name.

Creating New Permissions

Each API that provides access to protected functionality defines its own permissions. The MIDP Specification version 2.0 defines permissions for its protected APIs. APIs defined outside of the MIDP Specification version 2.0 must have a single document that specifies any necessary permissions and the behavior of the API when it is implemented for MIDP 2.0.

18.3.2 Requesting Permissions for a MIDlet Suite

A MIDlet suite might require access to some protected APIs or functions and consider access to others optional. A MIDlet suite that requires access to protected APIs or functions must request the corresponding permissions by listing them in the MIDlet-Permissions attribute of its JAR manifest or application descriptor (JAD). A MIDlet should list permissions using this attribute only if the permissions are critical to the function of the MIDlet suite (that is, the MIDlet will not operate correctly without them).

A MIDlet suite that can use protected APIs, but can function correctly without them, should request the corresponding permissions by listing them in the MIDlet-Permissions-Opt attribute of its JAR manifest or application descriptor. The MIDlet suite should be able to run with reduced functionality without these non-critical permissions. For example, perhaps the user can play a game MIDlet as a single-player game if the permissions cannot be granted, instead of as a network-aware game.

For example, to require permission to be launched for an alarm (a PushRegistry function) and to conditionally require a SecureConnection, a MIDlet suite would use the following attribute-value pairs in its JAR manifest or application descriptor:

MIDlet-Permission: javax.microedition.io.PushRegistry
MIDlet-Permission-Opt: javax.microedition.io.Connector.ssl

Multiple permissions are separated by a comma. Leading and trailing white space and tabs are ignored.

18.3.3 Protection Domain

A protection domain defines a set of permissions and related interaction modes. (See Section 18.3.4, "Interaction Modes for User Permissions," for more information.) A device places each MIDlet suite into a protection domain. The domain's permissions are the only permissions that the device can grant to the MIDlets of the suite. For example, Section 18.2, "Sandbox for Untrusted MIDlet Suites," covered the access rights in the untrusted domain.

A protection domain consists of permissions that are either:

  • Allowed: MIDlet suites in the protection domain are given access to the protected function without any user interaction.

  • User: MIDlet suites in the protection domain are given access to the protected function only after the user authorizes it. The implementation must give the user a prompt, and the user can choose a user permission interaction mode (see the next subsection) or deny the request.

18.3.4 Interaction Modes for User Permissions

A User permission requires the user to either deny permission to use a specific API or function or to grant permission by choosing one of the following interaction modes:

  • blanket: Grants permission for every invocation of an API or function by the MIDlet suite until it is uninstalled or the permission is changed by the user.

  • session: Grants permission for invocations of an API or function by the MIDlet until the MIDlet terminates. A session interaction mode must prompt the user on or before the first invocation of the protected API or function. When the user relaunches the MIDlet suite, the prompt must be repeated.

  • oneshot: Grants permission for only the current invocation of an API or function. A oneshot interaction mode must prompt the user on each invocation of the protected API or function.

The security policy of the device implementation determines the choice of interaction modes for user permissions. The policy defines, for each user permission, the default interaction mode and a set of other interaction modes from which the user may choose. The implementation may offer the user the default interaction mode if it is supplied.

18.3.5 Granting Permissions to Trusted MIDlet Suites

The process of authorizing a MIDlet suite is established by the relationships between:

  • A set of permissions for the protected APIs and functions on the device. This is a union of all permissions defined by every API on the device for protected functions.

  • A protection domain consisting of a set of Allowed and User permissions.

  • A set of permissions requested by the MIDlet suite in the MIDlet-Permissions and MIDlet-Permissions-Opt attributes of its JAR manifest or application descriptor.

  • The user who may be asked to grant permissions.

To authorize a trusted MIDlet suite, the MIDlet suite must be in a protection domain. In addition, the MIDP implementation must have gotten the critical and non-critical permission requests from its JAR manifest or application descriptor, and must remove from consideration any non-critical permissions that are unknown to it. The permissions that can be granted to the MIDlet suite are the intersection of the requested permissions with the union of the Allowed and user-granted permissions in the protection domain.

A MIDP implementation authorizes a MIDlet suite for the first time when the user tries to install it. The MIDlet suite must meet the following authorization requirements, or it will not be installed:

  • If the MIDlet-Permissions and MIDlet-Permissions-Opt attributes are in both the application descriptor and in the JAR manifest, their values must be identical. If the values are not identical, the system will not install the MIDlet suite.

  • All requested critical permissions must be known to the implementation. If any of the requested critical permissions are unknown, the MIDlet suite is not installed and cannot be launched.

  • All requested critical permissions must be present in the protection domain. If any of the requested critical permissions are not present in the protection domain, the MIDlet suite is not installed and cannot be launched.

A MIDP implementation also authorizes a MIDlet suite when it tries to access a protected API. (During execution, protected APIs must check for the appropriate permissions.) If the MIDlet's protection domain protects the security-sensitive API with a User permission, the user must provide authorization in order to grant those permissions to the MIDlet suite. The MIDP implementation is responsible for making the request to the user and getting the response to allow or deny the request. When the implementation prompts the user, it should provide a description of the requested permissions that is clear enough to enable a well-informed choice. The user must always be able to deny permission.

The result of a successful authorization is that the MIDlet suite is granted access to the protected API. If the permission was not granted, the protected API must throw a SecurityException.


18.4 APIs That Are Not Security Sensitive

APIs and functions that are not security sensitive are accessible by all MIDlet suites. These APIs are listed in Table 18.3.

Table 18.3. APIs freely permitted for all MIDlet suites

API

Description

javax.microedition.rms

RMS APIs

javax.microedition.midlet

MIDlet Life-cycle APIs

javax.microedition.lcdui

User Interface APIs

javax.microedition.lcdui.game

The Game APIs

javax.microedition.media
javax.microedition.media.control

The multimedia APIs for playback of sound


18.5 Establishing Trust for MIDlet Suites by Using X.509 PKI

The mechanisms for signing and authenticating MIDlet suites are based on Internet standards for public key cryptography RFC 2437 [reference 6], RFC 2459 [reference 7], RFC 2560 [reference 8], and WAPCERT [reference 15].

A developer can put a digital signature of the MIDlet suite's JAR and a certificate in the MIDlet suite's application descriptor. A digital signature is a piece of data, created with the private key of a private-public key pair, that ensures the JAR has not been tampered with.

A certificate contains the corresponding public key that can be used to check the digital signature in the JAR and the signature of an entity that vouches that the public key in the certificate is genuine. The application descriptor can also have another certificate that contains the public key of the vouching entity and the signature of the entity that vouches for it. This can continue until there is a certificate for a well-known and trusted entity that does not need another entity to vouch for it; it vouches for itself. Such an entity is called a certificate authority (CA), and the certificate is said to be self-signed. Self-signed certificates are also called root certificates. Root certificates reside on the device, not in the application descriptor. A series of certificates that begins with the JAR signer and ends with a CA is called a certificate chain.

Normally the development environment for MIDP applications will include tools to handle signing of a MIDlet suite and putting the appropriate certificates into the suite's application descriptor, so application developers should not have to understand these details. However, developers may still need to be aware of the protection domains on their target devices so that they can obtain the appropriate certificates.

When a user tries to install a signed MIDlet suite, the device authenticates the suite by verifying the signer certificates and JAR signature. Authentication enables the device to assign the MIDlet suite to a protection domain and appropriately authorize the MIDlets. Devices associate protection domains with CAs. For example, the device might assign the MIDlet suites that use the device manufacturer for their root certificate to one domain and the MIDlet suites that use the MIDP implementor for their root certificate to another. The root certificate associated with a protection domain is called the protection domain root certificate.

In the case where there is a trusted relationship (possibly bound by legal agreements), the owner of a protection domain root certificate may delegate signing MIDlet suites to a third party and, in some circumstances, the author of the MIDlet.

18.5.1 Signing a MIDlet Suite

The signer of a MIDlet suite might be the developer or an entity responsible for distributing, supporting, and perhaps billing for the use of the MIDlet suite. The signer is responsible for ensuring that the MIDlet suite's applications are not malicious and will not harm assets or capabilities. The signer must exercise due-diligence in checking the MIDlet suite before signing it.

The signer must have a private and public key pair. The signer uses the private key to sign the MIDlet suite, and provides the public key in an RSA X.509 certificate for the MIDlet suite's application descriptor. That certificate might be validated by another certificate, and so on, except for the final certificate in the application descriptor. The final certificate in the application descriptor is validated by a protection domain root certificate on the device.

The signature of a MIDlet suite protects only the JAR containing the manifest, the MIDlets' classes, and any additional resources. The signature does not protect the application descriptor; it is not secured. Attributes defined within the manifest are protected by the signature, but attributes in the application descriptor are not.

Because attributes defined in the application descriptor are not secured, when an attribute appears in the manifest, it must not be overridden by a different value from the application descriptor. For trusted MIDlet suites, the value in the application descriptor must be equal to the value of the corresponding attribute in the manifest. If not, the MIDlet suite must not be installed. The MIDlet.getAppProperty method returns the attribute value from the manifest if one is defined. If not defined, the value from the application descriptor, if any, is returned.

Note that the requirement for attribute values to be equal differs from MIDP 1.0 and must be used for applications that are signed and verified by these procedures. For untrusted MIDlet suites, the MIDP 1.0 rule gives priority to application descriptor attributes instead of manifest attributes.

Examples of MIDlet Suite Signing

There are many ways to structure protection domain root certificates and their associated signing policies. These examples show two possibilities.

Example 1 – Developer Owns Signing Certificate

This example covers the case where the developer owns the signing certificate and uses it to sign the application. In this case, the origin of the MIDlet suite is encoded into the application descriptor; it is the identity of the signer.

  1. Developer creates a MIDlet.

  2. Developer encodes permission requests into the JAR's manifest and creates a final MIDlet suite JAR.

  3. Developer generates a private-public key pair with a signing certificate and has the certificate signed by one or more protection domain root certificates.

  4. Developer's certificate is used to sign the MIDlet's JAR and create the associated entries in the application descriptor.

  5. MIDlet suite can be distributed with a suitably populated application descriptor and run on a MIDP 2.0-compliant device that has an appropriate protection domain root certificate, as long as the certificate is valid.
Example 2 – Protection-Domain Stakeholder Owns Signing Certificate

This example covers the case where the signer's identity (not the MIDlet suite developer) is encoded into the application descriptor.

  1. Developer creates a MIDlet.

  2. Developer encodes permissions into the JAR's manifest and creates a final MIDlet JAR.

  3. The protection domain stakeholder's signing certificate (not necessarily the root certificate) is used to sign the MIDlet JAR and create the associated entries in the application descriptor.

  4. The MIDlet suite can be distributed with a suitably populated application descriptor and run on a MIDP 2.0-compliant device that has an appropriate protection domain root certificate, as long as the certificate is valid.
Creating the Signing Certificate

The signer will need to be aware of the authorization policy for the target device and identify which protection domain the MIDlet suite should operate in. The domain's protection domain root certificate must be the root of the certificate chain. The signer will need to contact the appropriate certificate authority. At the time of this writing, the best place to begin to determine the correct domain and certificate authority is to contact the developer program of the network operator or the device manufacturer. The signer might need to send its distinguished name (DN) and public key (normally, packaged in a certificate request) to the certificate authority who would create a RSA X.509 (version 3) certificate and return it to the signer.

If the MIDlet suite will need to run on devices with different protection domains or protection domain root certificates, then the signer would need to use the same public key for verification but get a different signing certificate from each certificate authority. All of the signer certificates in the MIDlet suite's application descriptor must contain the same public key.

The signer should also remain aware of the certificate's status. If the certificate expires, new installs will not succeed. If the certificate is disabled or revoked, every user on every device that supports revocation will have their execution permissions revoked.

Inserting Certificates into the Application Descriptor

The certificate chain, except the root certificate, must be included in the application descriptor. The root certificate will be found on the device. Each certificate in the path is encoded (using base64 but without line breaks) and inserted into the application descriptor as:

MIDlet-Certificate-n-m: base64-encoding-of-certificate

The certificates are numbered to define the sequence in which they are examined. The number n is one (1) for the first certificate chain in the descriptor. The number n should increment by one for each subsequent certification chain. The order defines the sequence in which the certificate chains are tested to see if the corresponding root certificate exists on the device. The number m is one (1) for the signer's certificate in a certification chain and increments by one for each subsequent intermediate certificate (if any).

Creating the RSA SHA-1 Signature of the JAR

The signature of the MIDlet suite JAR is created with the signer's private key according to the EMSA-PKCS1-v1_5 encoding method of PKCS #1 version 2.0 standard [reference 6]. The signature is base64 encoded, formatted as a single MIDlet-Jar-RSA-SHA1 attribute without line breaks and inserted in the application descriptor.

MIDlet-Jar-RSA-SHA1: base64-encoding-of-Jar-signature

18.5.2 Authenticating a MIDlet Suite

When a MIDlet suite is downloaded, a device that recognizes MIDlet suites signed using PKI as trusted must check whether authentication is required. If the attribute MIDlet-Jar-RSA-SHA1 is present in the application descriptor, then the JAR must be authenticated by verifying the signer certificates and JAR signature. Application descriptors without the MIDlet-Jar-RSA-SHA1 attribute are not authenticated but are installed and invoked as untrusted MIDlet suites.

Verifying the Signer's Certificate

When a device verifies the signer certificate, it tries to find a certificate chain that ends with a root certificate on the device. (Root certificates may also be present in removable media such as a SIM(WIM) card or a USIM module. The device implicitly trusts these roots to verify the integrity and authentication of MIDlet suites.)

To verify a signature, the device extracts a certificate chain from the application descriptor. It first gets attributes MIDlet-Certificate-1-m, where m starts at one and increments by one until there is no attribute with the given name. The value of each attribute is a base64-encoded certificate that it must decode and parse. The device validates the certificate chain using the basic path validation processes described in RFC 2459 [reference 7] with the protection domains as the authoritative source of protection domain root certificates. The MIDlet suite is bound to the protection domain that contains the protection domain root certificates that validates the first chain from signer to root and proceed with installation.

If no protection domain root certificate validates the first chain, the device checks for other certificate chains. If there are multiple chains present, the device should check the chain with the attributes MIDlet-Certificate-2-m, and so on, until a chain can be validated or there are no more chains to check. Table 18.4 indicates how the results of certificate verification are acted upon.

Table 18.4. Actions upon completion of signer certificate verification

Outcome of Certificate Chain Validation

Subsequent Action

Attempted to validate n paths, but no public keys of the issuer of the certificate can be found or none of the certification paths can be validated.

Authentication fails; the MIDlet suite will not be installed.

More than one full certificate path established and validated.

Installation proceeds using the first successfully verified certificate path; next step is verification of the JAR signature.

Only one full certificate path established and validated.

Implementation proceeds; next step is verification of the JAR signature.

Verifying the MIDlet Suite JAR

The MIDlet suite JAR is verified to insure the integrity of the application. The MIDlet-Jar-RSA-SHA1 attribute is retrieved from the application descriptor and decoded from base64 yielding a PKCS #1 signature. The signer's public key from the signer certificate is used to verify the signature. If the signature verification fails, the MIDlet suite is rejected.

The SHA-1 hash of the MIDlet suite JAR must match the message digest in the signature. If it does not match, the device must not install the JAR or allow MIDlets from the MIDlet suite to be invoked.

Once the steps of verifying the certificate, verifying the signature, and verifying the JAR all succeed, the MIDlet suite contents are known to be intact and the identity of the signer is known.

Results of MIDlet Suite Source Verification

It is essential that the steps performed to verify the digital signature as previously described lead to proof of the identity of the MIDlet suite signer. The results of the verification have a direct impact on authorization. Table 18.5 summarizes the state in which the device found the MIDlet suite and where the signature verification led.

Table 18.5. Summary of MIDlet suite source verification

Initial State of MIDlet Suite

Verification Result

Implications for Authorization

JAD not present.

JAR was downloaded.

Authentication cannot be performed.

Installation permitted; MIDlet suite is treated as untrusted.

JAD present.

JAR is unsigned.

Authentication cannot be performed.

Installation permitted MIDlet suite is treated as untrusted.

JAR signed.

No root certificate on the device to validate the certificate chain.

Authentication cannot be performed.

Installation not permitted.

JAR signed.

A certificate on the path is expired.

Authentication cannot be completed.

Installation not permitted.

JAR signed.

A certificate rejected for reasons other than expiration.

JAD rejected;

authentication failed.

Installation not permitted.

JAR signed.

Certificate path validated Signature verification fails.

JAD rejected;

authentication failed.

Installation not permitted.

JAR signed.

Certificate chain validated Signature verified.

Authentication succeeded.

Installation permitted; MIDlet suite assigned to the protection domain associated with the corresponding protection domain root certificate.

18.5.3 Caching of Authentication and Authorization Results

The authentication and authorization processes may store and transfer their results for subsequent use. The MIDP implementation must protect the cached information so that it cannot be tampered with or otherwise compromised between the time it is computed and the time the authorization information is used.

It is also essential that the MIDlet suite and security information used to authenticate and authorize a MIDlet suite (that is, the raw material for the authentication and authorization process) is not compromised. This could happen, for example, if the implementation used removable media or other MIDlet suite storage that might be corrupted.

18.5.4 X.509 Certificate Profile for Trusted MIDlet Suites

Secured, trusted MIDlet suites use the same base certificate profile as HTTPS. The profile is based on the WAP Certificate Profile, WAP-211-WAPCert-20010522-a [reference 15] which is based on RFC 2459 [reference 7]. See Section 16.4, "MIDP X.509 Certificate Profile," for more information.

Certificate Processing for Over-The-Air (OTA) Delivery

Devices must recognize the key usage field. When the field is present, the device must verify that it has the digitalSignature bit set.

Devices must recognize the critical extended key usage field. When the field is present, the device must verify that the extension contains the id-kp-codeSigning object identifier. (See RFC 2459 section 4.2.1.13 [reference 7].)

The application descriptor should not include a self-signed root certificate in a certificate chain. However, MIDP devices should treat the certificate as any other in a chain and not explicitly reject a chain that contains a X.509v3 self-signed CA certificate.

Certificate Expiration and Revocation

A device checks expiration and, optionally, revocation of certificates supplied in the application descriptor during the authorization procedure. A device can check for certificate expiration locally because it can get the information from the certificate itself. Certificate expiration verification is an intrinsic and mandatory part of certificate path validation.

Certificate revocation is a more complex check, because a device has to send a request to a server and make a decision based on the response. A device can perform certificate revocation, but such mechanisms are not part of MIDP implementation and hence do not form a part of MIDP 2.0 security framework. If a device implements certificate revocation, it should support Online Certificate Status protocol (OCSP) [reference 8]. If other certificate revocation protocols are supported, and they indicate that a certificate has been revoked, the device may consider the certificate as revoked regardless of the result returned by the OCSP protocol.


18.6 Recommended Security Policy for GSM/UMTS Devices

The MIDP Specification defines the security model and mechanisms to determine whether applications can be trusted, and for them to request specific permissions. The specification does not mandate a specific policy or how those mechanisms are used. The Recommended Security Policy for GSM/UMTS Devices (see the MIDP Specification version 2.0) describes a policy recommended by the GSM operators. The purpose of the policy is to allow consistent application behavior across GSM and UMTS devices and networks.


18.7 New for MIDP 2.0

The entire security model for MIDlet suites is new in MIDP 2.0. Unlike in MIDP 1.0, the MIDlets are no longer restricted to run only in a sandbox. Flexible mechanisms are now provided to establish a security policy for a MIDP device. The new model is extensible for use with J2ME optional packages and other APIs such as the Wireless Messaging API and the Mobile Media API. The new model can take advantage of the existing PKI infrastructure to ensure the integrity and authentication of the source of MIDlet suites. Through the protection domains, the new model enables the implementation of a variety of security policies that meet the needs of security-critical mobile applications and business models.


Chapter 19. MIDlet Deployment

Deploying MIDlets involves more than simply writing Java code using the CLDC and MIDP APIs. To transfer the MIDlet to a wireless device, it has to be packaged with the resources it requires, configured for the locale in which it will be used, and placed on a server that supports the over-the-air (OTA) protocol specification so that it can be downloaded by mobile devices. The first thing to understand is the concept of a MIDlet suite.


19.1 MIDlet Suites

One of the central goals for the MIDP application model is to provide support for the controlled sharing of data and resources between multiple, possibly simultaneously running MIDlets. To accomplish this goal while retaining a secure environment, the MIDP Specification requires that any MIDlets needing to interact and share data beyond what is enabled with the RMS record sharing in MIDP 2.0 (refer to Section 14.2.2, "Shared Record Stores"), the MIDlets must be placed into a single JAR. This collection of MIDlets encapsulated in a JAR is referred to as a MIDlet suite.

The MIDlets within a MIDlet suite share a common name space (for persistent storage), runtime object heap, and static fields in classes. In order to preserve the security and the original intent of the MIDlet suite provider, the MIDlets, classes, and individual files within the MIDlet suite cannot be installed, updated, or removed individually—they must be manipulated as a whole. In other words, the basic unit of application installation, updating, and removal in MIDP is a MIDlet suite.

A MIDlet suite can be characterized more precisely by its packaging and its runtime environment. These characteristics are discussed in more detail next.

19.1.1 MIDlet Suite Packaging

A MIDlet suite is encapsulated within a JAR.[1] A MIDlet suite provider is responsible for creating a JAR that includes the appropriate components for the target user, device, network, and locale. For example, since the CLDC Specification does not include the full internationalization and localization support provided by Java 2 Standard Edition, a MIDlet suite provider must tailor the JAR components to include the necessary additional resources (strings, images, and so forth) for a particular locale.

[1] JAR format specifications are available at http://java.sun.com/products/jdk/1.4.1/docs/guide/jar/index.html . Refer to the JDK JAR and manifest documentation for syntax and related details.

The contents of the MIDlet suite's JAR include the following components:

  • the class files implementing the MIDlet(s),

  • any resource files used by the MIDlet(s)—for example, icon or image files, and so forth, and

  • a manifest describing the JAR contents.

All the files needed by the MIDlet(s) are placed in the JAR using the standard structure based on mapping the fully qualified class names to directory and file names within the JAR. Each period is converted to a forward slash, '/'. For class files, the .class extension is appended.

19.1.2 Application Descriptor

Each JAR may be accompanied by an optional[2] application descriptor (JAD file.) The application descriptor allows the application management software on the device to verify that the associated MIDlet suite is suitable for the device before loading the full JAR. It also allows MIDlet attributes to be supplied to the MIDlet suite without modifying the JAR.

[2] The application descriptor is optional for distributors of MIDlet suites (such as wireless network operators). However, all MIDP-compliant implementations must accept an application descriptor.

The application descriptor that has the MIME type 'text/vnd.sun.j2me.app-descriptor' and the file name extension '.jad'.

The contents of the application descriptor are described by the following BNF syntax:

appldesc: *attrline
attrline: attrname ":" WSP attrvalue WSP newlines
attrname: 1*<any Unicode char except CTLs or separators>
attrvalue: *valuechar | valuechar *(valuechar | WSP) valuechar
valuechar: <any valid Unicode character, excluding CTLs and WSP>
newlines = 1*newline ; allow blank lines to be ignored
newline: CR LF | LF
CR = <Unicode carriage return (0x000D)>
LF = <Unicode linefeed (0x000a)>
WSP: 1*( SP | HT )
SP = <Unicode space (0x0020)>
HT = <Unicode horizontal-tab (0x0009)>
CTL = <Unicode characters 0x0000 - 0x001F and 0x007F>
separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "'" | <">
           | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT

19.1.3 MIDlet Attributes

The JAR manifest and application descriptor provide a means to encode information about the contents of the JAR. In particular, the JAR manifest specification provides for name-value pairs that MIDP uses in the manifest and application descriptor to encode MIDlet attributes. MIDlet attribute names are case-sensitive.

A predefined set of attributes is specified to allow the application management software to identify, retrieve, and install the MIDlet(s). Attribute names that start with "MIDlet-" or "MicroEdition-" are reserved for use by the MIDP expert group to define MIDP-specific MIDlet attributes. MIDlet suite developers can define their own MIDlet attributes provided that the new attributes do not start with the reserved "MIDlet-" or "MicroEdition-" prefixes. The MIDP Specification currently defines the MIDlet attributes shown in Table 19.1 on page 328. All attributes appearing in the application descriptor are made available to the MIDlet(s) through the MIDlet.getAppProperty method.

In general, attributes can be located in either the application descriptor or the JAR manifest; however, some attributes must be located in specific places, as described next.

Of the predefined attributes in Table 19.1 on page 328, the following must be in the JAR manifest:

  • MIDlet-Name

  • MIDlet-Version

  • MIDlet-Vendor

The following attributes must be in the application descriptor, if present:

  • MIDlet-Name

  • MIDlet-Version

  • MIDlet-Vendor

  • MIDlet-Jar-URL

  • MIDlet-Jar-Size

The manifest or the application descriptor must contain the following attributes:

  • A MIDlet-<n> for each MIDlet

  • MicroEdition-Profile

  • MicroEdition-Configuration

The manifest or the application descriptor can additionally contain the following attributes:

  • MIDlet-Description

  • MIDlet-Icon

  • MIDlet-Info-URL

  • MIDlet-Data-Size

  • MIDlet-Permissions

  • MIDlet-Permissions-Opt

  • MIDlet-Push-<n>

  • MIDlet-Install-Notify

  • MIDlet-Delete-Notify

  • MIDlet-Delete-Confirm

  • Any application-specific attributes that do not begin with "MIDlet-" or "MicroEdition-"

A rudimentary form of version control between the JAR and the application descriptor is ensured by requiring that the attribute values for MIDlet-Name, MIDlet-Version, and MIDlet-Vendor be identical in the JAR manifest and the application descriptor. If they are not, then the system will assume a version mismatch, and the MIDlet suite will not be installed. All other MIDlet attributes names may also be duplicated. In the case of untrusted MIDlets, the values from the application descriptor will override the values from the JAR manifest. In the case of trusted MIDlets the values must be identical. See Section 18.3, "Trusted MIDlet Suite Security Model," for an expanded description of the trusted MIDlet security model.

As an example, the following shows a JAR manifest for a hypothetical MIDlet suite of card games provided by Motorola. The suite contains two MIDlets: Solitaire and JacksWild:

MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: Motorola
MIDlet-1: Solitaire, /Solitaire.png, com.motorola.Solitaire
MIDlet-2: JacksWild, /JacksWild.png, com.motorola.JacksWild
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.1

The corresponding application descriptor for this MIDlet suite would look like this:

MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: Motorola
MIDlet-1: Solitaire, /Solitare.png, com.motorola.Solitare
MIDlet-2: JacksWild, /JacksWild.png, com.motorola.JacksWild
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.1
MIDlet-Description: Really cool card games
MIDlet-Jar-URL: http://www.cardsrus.com/games/cardgames.jar
MIDlet-Jar-Size: 7378
MIDlet-Data-Size: 256

Table 19.1. MIDlet attributes

Attribute Name

Description

MIDlet-Name

The name of the MIDlet suite that identifies the MIDlets to the user.

MIDlet-Version

The version number of the MIDlet suite. The format is major.minor.micro, as described in the JDK Product Versioning Specification (see http://java.sun.com/products/jdk/1.2/docs/guide/versioning/spec/VersioningSpecification.html). It can be used by the system for installation and upgrade uses, as well as communication with the user. Default value is 0.0.0.

MIDlet-Vendor

The organization that provides the MIDlet suite.

MIDlet-Icon

The case-sensitive absolute path name of a PNG file within the JAR, which represents the MIDlet suite to the user.

MIDlet-Description

A short description of the MIDlet suite.

MIDlet-Info-URL

A URL for information further describing the MIDlet suite.

MIDlet-<n>

The name, icon, and class of the nth MIDlet in the JAR separated by a comma. The lowest value of <n> must be 1 and consecutive ordinals must be used.

Name is used to identify the MIDlet to the user.

Icon (optional) is the case-sensitive absolute path name of an image (PNG) within the JAR that the system should use for the icon of the nth MIDlet.

Class is the name of the MIDlet class for the nth MIDlet.

MIDlet-Jar-URL

The URL from which the JAR was loaded.

MIDlet-Jar-Size

The size of the JAR in bytes.

MIDlet-Data-Size

The minimum number of bytes of persistent data required by the MIDlet. The default is zero.

MicroEdition-Profile

The J2ME profiles required, using the same format and value as the system property microedition.profiles (for example "MIDP-2.0"). The device must implement all of the profiles listed or the installation will not be attempted. Multiple profiles are separated with a blank (Unicode U+0020).

MicroEdition-Configuration

The J2ME Configuration required using the same format and value as the system property microedition.configuration (for example "CLDC-1.1").

MIDlet-Permissions

Zero or more permissions that are critical to the function of the MIDlet suite. See Section 18.3, "Trusted MIDlet Suite Security Model," for details of usage.

MIDlet-Permissions-Opt

Zero or more permissions that are non-critical to the function of the MIDlet suite. See Section 18.3, "Trusted MIDlet Suite Security Model," for details of usage.

MIDlet-Push-<n>

Register a MIDlet to handle inbound connections. Refer to Section 17.2.2, "Mechanics of Static Push Registration," for details.

MIDlet-Install-Notify

The URL to which a POST request is sent to report the installation status (whether a new installation or MIDlet suite update) of this MIDlet suite.

MIDlet-Delete-Notify

The URL to which a POST request is sent to report the deletion of this MIDlet suite.

MIDlet-Delete-Confirm

A text message to be provided to the user when prompted to confirm deletion of this MIDlet suite.

19.1.4 MIDlet Suite Execution Environment

The MIDP Specification defines the environment in which MIDlets within a suite execute. This environment is shared by all MIDlets within a MIDlet suite, and any MIDlet can interact with other MIDlets packaged in a suite. The runtime environment is logically composed of name spaces, as depicted in Figure 19.1. These name spaces determine how a MIDlet accesses an entity within that name space.

Figure 19.1. MIDlet suite name spaces

The logical name spaces in a MIDlet's runtime environment are as follows:

  • Classes and native code that implement the CLDC and MIDP as well as any other CLDC profiles, optional packages, and licensee open classes. This is the only name space that is shared by all MIDlet suites on the device.

  • Classes within the MIDlet suite's JAR.

  • All non-class files in the MIDlet suite's JAR, such as icon or image files, and the JAR manifest. These files are accessible via the method java.lang.Class.getResourceAsStream.

  • The contents of the Java Application Descriptor (JAD). The contents are accessible via the method javax.microedition.midlet.MIDlet.getAppProperty. (Note: the JAR manifest attributes are also accessible via this method.)

  • A separate name space for RMS record stores (see Chapter 14, "MIDP Persistence Libraries").

All the classes needed by a MIDlet within a suite must be in the JAR or in the system libraries (system libraries typically include the CLDC and MIDP libraries as well as optional packages and manufacturer-specific libraries.) A MIDlet may load and invoke methods from any class in the JAR or in the system libraries. All of the classes within these scopes are shared in the execution environment, along with a single heap containing the objects created by MIDlets, MIDP libraries, and CLDC libraries. The usual locking and synchronization primitives of the Java programming language can be used where necessary to avoid concurrency problems.

The class files of the MIDlet are only available for execution and can neither be read as resources nor extracted for reuse, since the underlying CLDC implementation may store and interpret the contents of the JAR in any manner suitable for the device.

The non-class files within the JAR, including the JAR manifest, can be accessed using the method java.lang.Class.getResourceAsStream. The parameter to this method, a String object, represents a path that is interpreted in the following manner: If it begins with a '/', the search for the resource begins at the "root" of the JAR; however, if it does not begin with a '/', the resource is searched for along a path relative to the class instance retrieving the resource. For example, if a JAR has the following contents as shown in this JAR manifest:

META-INF/
META-INF/MANIFEST.MF
examples/
examples/HelloWorld.class

then, in the following code fragment, both getResourceAsStream calls will open an InputStream to the manifest.

Class C = Class.forName("examples.HelloWorld");
InputStream s1 = C.getResourceAsStream("/META-INF/MANIFEST.MF");
InputStream s2 = C.getResourceAsStream("../META-INF/MANIFEST.MF");


19.2 MIDP System Software

In the preceding sections and chapters, frequent references were made to the piece of software called the "system," "MIDP system," or the "execution environment." The MIDP Specification calls this software the application management software, or the AMS. In some documents, application management software is also referred to as the Java Application Manager, or the JAM. The two terms (AMS and JAM) are equivalent.

The application management software in a MIDP implementation consists of those pieces of software on the device that provide a framework in which MIDlet suites are installed, updated, removed, started, stopped, and in general, managed. Furthermore, the application management software provides MIDlets with the runtime environment discussed in Section 19.1.4, "MIDlet Suite Execution Environment."


19.3 Over-the-Air User-Initiated Provisioning

MIDP devices without installed MIDlets would not be all that useful. Granted, a device may provide a way to download MIDlets through serial cable or similar mechanism, which would enable the installation of MIDlets. However, one of the biggest advantages of recent devices is the availability of wireless data connectivity, whereby the device can connect with Internet servers and services to download MIDlets over-the-air (OTA). In this way, the user can have access to new MIDlets while in the airport, train station, at a friend's house, in a meeting, or generally anywhere where wireless coverage is available.

In the MIDP Specification version 2.0, the OTA download specification is based on the HTTP protocol.[3] While the most common way a user will discover MIDlet suites for downloading will be through the WWW, WAP, or iMode browser resident on the device, other solutions are possible. For the specification and this book, we will use the more generic term discovery agent (DA) to indicate the application used for discovering and downloading a MIDlet suite.

[3] The term HTTP protocol is used generically in this chapter to mean HTTP and HTTPS, as well as the WAP protocol (WSP) with the http:// schema.

For the sake of simplicity in the rest of this discussion, we will ignore the intermediate wireless base stations, network nodes, and other network components, and consider the OTA transaction as a direct connection between the mobile device and a server.

A typical transaction is illustrated in the event transition diagram in Figure 19.2, and it consists of the following steps:

  1. Using the discovery agent (DA), the user chooses a MIDlet to install. The MIDlet will be referenced by a URL that points to either an Java Application Descriptor File (JAD) or a JAR.

  2. If the URL references an application descriptor, the device downloads it and examines its contents as a preflight check. In this way it ensures that the device has suitable capabilities and resources to run the MIDlet before attempting the download of the JAR, which is typically much larger.

  3. If the URL that the user chose represents a JAR, or if the application descriptor preflight check was successful, the device downloads the JAR and installs it.

  4. The device sends a notification to the server indicating the installation status, whether successful or not.
Figure 19.2. OTA download sequence. Italic items are optional.

19.3.1 MIDlet Suite Updates

If the MIDlet suite being requested for installation is already installed on the device (either the same version or a different version), the device treats this as a request to update the MIDlet suite. In this case the device will allow the user to obtain information about the MIDlet suite(s) on the device and determine what version of this MIDlet suite is installed, and it will notify the user if the MIDlet suite is a newer, older, or the same version of an existing MIDlet suite. It will then get confirmation from the user before proceeding.

The RMS record stores of a MIDlet suite being updated will be managed as follows:

  • If the cryptographic signer of the new MIDlet suite and the original MIDlet suite are identical, then the RMS record stores will be retained and made available to the new MIDlet suite.

  • If the scheme, host, and path of the URL that the new Application Descriptor is downloaded from is identical to the scheme, host, and path of the URL the original Application Descriptor was downloaded from, then the RMS will be retained and made available to the new MIDlet suite.

  • If the scheme, host, and path of the URL that the new MIDlet suite JAR is downloaded from is identical to the scheme, host, and path of the URL the original MIDlet suite JAR was downloaded from, then the RMS will be retained and made available to the new MIDlet suite.

  • If all of the above statements are false, then the device will ask the user whether the data from the original MIDlet suite should be retained and made available to the new MIDlet suite.

An unsigned MIDlet will not be allowed to update a signed MIDlet suite. The format, contents, and versioning of the record stores is the responsibility of the MIDlet suite. The user-granted permissions given to the original MIDlet suite will usually also be given to the new MIDlet suite, if they are in the security domain of the new MIDlet suite.

19.3.2 MIDlet Suite Removal

When a MIDlet suite is to be removed from the device, the user will usually be prompted to confirm that the MIDlet suite may be removed. The device will usually warn the user of any special circumstances that arise during the deletion of the MIDlet suite. For example, the MIDlet suite could contain multiple MIDlets, and the user should be made aware that all of the MIDlets and associated RMS record stores are being removed.

If the Application Descriptor includes the attribute MIDlet-Delete-Confirm, its value will usually be included in the prompt. This will allow the MIDlet suite provider to highlight any specific conditions that might arise if the MIDlet suite were to be removed.

19.3.3 Installation and Deletion Status Reports

The success or failure of the installation, upgrade, or deletion of a MIDlet suite is of interest to the service providing the MIDlet suite. The service can specify URLs in the Application Descriptor for reporting installation and deletion status. If the device cannot send the installation status report, the requested action will still be completed. For example, if the device cannot send the installation status report to the MIDlet-Install-Notify URL, the MIDlet suite will still be enabled, and the user will be allowed to use it. Likewise, if the device cannot send the deletion status report to the MIDlet-Delete-Notify URL, the MIDlet suite will still be deleted.

The operation status is reported by means of an HTTP POST to the URL specified in the MIDlet-Install-Notify attribute for installations, and by use of the MIDlet-Delete-Notify attribute for deletions. The only protocol that devices must support is "http://". Other protocols might be ignored by the device.

The content of the body of the POST request will include a status code and status message on the first line. See Table 19.2 for a list of valid codes and status messages.

In the case of a deletion status report, a notification with status code 912 is sent when the MIDlet is deleted.

In response to a status report, the server will reply with the standard HTTP "200 OK" response. No content should be returned to the device and, if any is sent, it will be ignored by the device.

For installations, if the status report cannot be sent, or if the server reply is not received, the installation status report might be sent again (as described above) each time a MIDlet in this suite is executed and the device has data network connectivity. This is optional behavior and would improve the likelihood of the status report being successfully sent, but each retry would likely result in a charge to the user's bill. The MIDlet suite will be made available for use, whether or not the installation status report has been successfully sent and the acknowledgement has been received.

For deletions, an attempt to send the status report will not be made immediately, but instead made the next time either an OTA installation is performed or an installation status report is being sent. This will improve the likelihood of the status report being successfully sent and will minimize confusion by the user when they see network activity. If the status report cannot be sent, or if the server reply is not received, the deletion status report may be sent again (as described above) each time an OTA installation is performed or an installation status report is being sent. The number of retries attempted should be kept small since each one may result in a charge to the user's bill. The MIDlet suite will be removed from memory whether or not the installation status report has been successfully sent and the acknowledgement has been received.

19.3.4 Installation Status Codes and Messages

Table 19.2 summarizes the status codes to be sent from client to server to report the status of installation.

Table 19.2. MIDlet status codes and status messages

Status Code

Status Message

900

Success

901

Insufficient memory

902

User cancelled

903

Loss of service

904

JAR size mismatch

905

Attribute mismatch

906

Invalid descriptor

907

Invalid JAR

908

Incompatible configuration or profile

909

Application authentication failure

910

Application authorization failure

911

Push registration failure

912

Deletion notification


19.4 New for MIDP 2.0

The MIDP Specification version 2.0 defines precise guidelines for the deployment and over-the-air (OTA) provisioning of MIDP applications, based on the experience that was gained after releasing the MIDP Specification version 1.0 and publishing the recommended practice document for the OTA delivery of MIDP 1.0 applications.

The result of this work is a streamlined specification that can be implemented on a wide range of devices and networks. Modifications have been made to the MIDlet suite model to handle the downloading and upgrading of signed MIDlet suites, and to handle failures related to the registration of MIDlet suites for event-based launching (using the PushRegistry class.) Support for cookies to identify sessions across download requests has been removed because that feature was difficult to support on some networks. Session information can be maintained using URL rewriting instead. Notifications can be requested by a provisioning server to indicate successful or unsuccessful installations and deletions. Attributes for the application descriptor and manifest are specified to allow the MIDlet suite to request permissions needed by the security model. The deployment specification allows a wide range of device implementations and provisioning servers to interoperate smoothly.


Chapter 20. Additional MIDP APIs

In addition to the functional categories discussed elsewhere in this book, the MIDP Specification defines some additional APIs that do not fill their own chapters. Also, the MIDP Specification intentionally modifies, refines, or augments the behavior of certain functions that it inherits from CLDC.

This chapter introduces the MIDP Timer APIs. Furthermore, this chapter discusses the system properties and resource access mechanisms defined by the MIDP Specification, as well as explains how the MIDP Specification overrides the behavior of the System.exit method inherited from CLDC.


20.1 Timer Support

MIDlets may need to delay or schedule activities to be performed at a later time. The MIDP Specification provides two mechanisms to enable this:

  • Timers are used for time-based events while a MIDlet is running. For example, a timer used to change the frame being shown in an animation sequence. Timers are covered in this section.

  • Alarms provide a one-shot time for MIDlets to be launched if they are not already running. Automatic launching can be convenient, for example, to register the next appointment in a calendar. Alarm-based MIDlet launching is covered in Section 17.1, "Alarm-Based MIDlet Launch."

The MIDP Specification provides two classes: Timer and TimerTask, that include functions for several types of timers. The general setup of a timer is illustrated next. In order to define a task to run, the programmer first defines a new timer task class by inheriting class TimerTask. The code to be executed by the timer is defined in the run method of the TimerTask subclass (see class MyTask below). In order to set up the actual timer, instances of class Timer and the new timer task class are created (objects myTimer and myTask in this example), and the schedule method of the timer object is then called with the task object and the appropriate time values as parameters. In this example, the timer will start executing in 10 milliseconds and will then repeat every 500 milliseconds.

class MyTask extends TimerTask {
    public void run() {
        ...
    }
}
...
myTimer = new Timer();
myTask = new MyTask();
myTimer.schedule(myTask, 10, 500);

There are two basic types of timers in MIDP: one-shot timers and repeating timers. The key difference between these two types of timers is the scheduling approach. A one-shot timer executes the specified task only once. A repeating timer continues executing the specified task repeatedly at a specific interval.

Timers can be used by a MIDlet in both the Active and Paused states, although use in the Paused state is discouraged.

20.1.1 Using One-Shot Timers

A one-shot timer can be set up to execute a task in two different ways. In the first approach, a java.util.Date object is passed into the schedule method of the Timer object. When the time specified by the Date object occurs, the timer task is run. If the Date passed in to the Timer object has already passed, then the timer task is run immediately. The following code fragment illustrates a timer whose task will be executed after 1000 milliseconds have passed after the current time (that is, after the time when the timer scheduling took place):[1]

[1] Keep in mind that MIDP Specification does not provide any real-time guarantees. There is no guarantee that the scheduled task would start exactly at the specified time. Usually, the scheduled tasks will start executing as soon as possible after the specified time.

myTimer.schedule(myTask,
                 new Date(System.currentTimeMillis() + 1000);

The second way to schedule a one-shot timer is by passing it a long value that contains the number of milliseconds to wait before executing the timer task. For instance, the following piece of code defines another timer whose task will be executed after 1000 milliseconds have passed:

myTimer.schedule(myTask, 1000);

20.1.2 Using Repeating Timers

The second type of timer supported by MIDP is a repeating timer. In this type of timer, the timer task is run repeatedly with a fixed period until the timer is canceled. Like one-shot timers, repeating timers can be set up to start executing the given task at a fixed time in the future (using a Date object as a parameter) or after a delay of a given number of milliseconds (using a long value as a parameter). In either case, the timer scheduling methods take an additional long parameter that indicates the repeat period of the timer. This period is interpreted either as a fixed-delay or a fixed-rate period, depending on whether the scheduling of the task is done using method schedule or scheduleAtFixedRate, respectively.

myTimer.schedule(myTask, 10, 500); // Fixed-delay repeating timer
myTimer.scheduleAtFixedRate(myTask, 10, 500); // Fixed-rate timer

In the fixed-delay case, each execution of the timer task is scheduled relative to the actual execution time of the previous timer task. If an execution is delayed for any reason, such as garbage collection or other background activity, subsequent executions will be delayed as well. This means that the execution of a fixed-delay timer may drift if, for example, the system is under a heavy execution load.

The fixed-rate case is different in that the execution of each timer task is scheduled relative to the scheduled execution time of the initial timer task. Thus, if an execution of a timer task is delayed for any reason, two or more executions will occur in rapid succession to "catch up" with the timer.

20.1.3 Sample Code (TimerMIDlet.java)

The following example illustrates the use of timers and timer tasks in more detail. In this example, two graphical gauges are created using the javax.microedition.lcdui APIs, and these gauges are incremented or decremented by timer tasks. (See the figure at left.) The MIDlet has two abstract commands attached: OK and EXIT. If the OK command is selected, then the state of the timers is changed from non-active to active, or from active to non-active, depending on the current state of the timers. The MIDlet will exit if the EXIT command is selected.

TimerMIDlet.java
package examples.timermidlet;

import java.lang.*;
import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

/**
 * A simple class that shows an example of using a Timer and
 * a TimerTask.
 *
 * This MIDlet creates two gauges. One gauge, gaugeOne,
 * sets elements from low to high. The other, gaugeTwo,
 * set elements from high to low. In effect, this has
 * gaugeOne "going up," and gaugeTwo "going down."
 *
 * The two timers fire at different intervals.
 *
 * There are two commands on our form:
 *
 * OK: toggles whether the times are active or not.
 * EXIT: exits the MIDlet.
 */

public class TimerMIDlet extends MIDlet implements CommandListener {
    // number of elements in gauge
    final private static int GAUGE_MAX = 10;

    private boolean timersRunning; // tracks state of timers
    private Display myDisplay;     // handle to the display

    private Gauge gaugeOne;        // "going up" gauge
    private Gauge gaugeTwo;        // "going down" gauge

    private Form myScreen;         // form on which to
                                   // place gauges
    private Command cmdOK;         // OK command
    private Command cmdExit;       // EXIT command

    private Timer timer;
    private MyTimerTask timerTaskOne;
    private MyTimerTask timerTaskTwo;

    /**
     * Internal class that provides a TimerTask.
     */
    private class MyTimerTask extends TimerTask {
        private Gauge myGauge; // reference to gauge
        private boolean goUp;  // if true, go up
        private int num;       // number of times called

        /**
        * Public constructor: stores "direction" and a reference to
         * a gauge.
         */
        public MyTimerTask(Gauge g, boolean up) {
            myGauge = g;
            goUp = up;
        }

        /**
         * As the timer fires, this method is invoked. Set gauge
         * based on goUp
         */
        public void run() {
            num++;
            myGauge.setValue(goUp ?
                             GAUGE_MAX -(num % GAUGE_MAX) :
                             num % GAUGE_MAX);
        }
    }

    /**
     * Public constructor: gets handle to display,
     * creates form, gauges, and commands.
     */
    public TimerMIDlet() {
        myDisplay = Display.getDisplay(this);
        myScreen = new Form("TimerMIDlet");
        gaugeOne = new Gauge("Up Gauge",
                             false,
                             GAUGE_MAX,
                             0);
        myScreen.append(gaugeOne);

        gaugeTwo = new Gauge("Down Gauge",
                             false,
                             GAUGE_MAX,
                             GAUGE_MAX);
        myScreen.append(gaugeTwo);

        cmdOK = new Command("OK", Command.OK, 1);
        cmdExit = new Command("Exit", Command.EXIT, 1);
        myScreen.addCommand(cmdOK);
        myScreen.addCommand(cmdExit);
        myScreen.setCommandListener(this);
    }

    /**
     * Changes the state of timers to/from active to/from
     * not active.
     */
    private void flipFlop() {
        if (timersRunning) {
            timerTaskOne.cancel();
            timerTaskTwo.cancel();
            timer.cancel();
            timersRunning = false;
        } else {
            timer = new Timer();
            timerTaskOne = new MyTimerTask(gaugeOne, false);
            timerTaskTwo = new MyTimerTask(gaugeTwo, true);
            timer.schedule(timerTaskOne, 0, 1000);
            timer.schedule(timerTaskTwo, 0, 1500);
            timersRunning = true;
        }
    }

    /**
     * Called by the system to start our MIDlet.
    * @exception MIDletStateChangeException
     */
    protected void startApp() throws MIDletStateChangeException {
        myDisplay.setCurrent(myScreen);
        flipFlop();
    }

    /**
     * Called by the system to pause our MIDlet.
     * No actions required by our MIDLet.
     */
    protected void pauseApp() {}

    /**
     * Called by the system to end our MIDlet.
     * No actions required by our MIDLet.
     */
    protected void destroyApp(boolean unconditional) {}

    /**
     * Respond to command selections. Process two commands:
     *
     * OK: flip flop the timers to/from active
     * EXIT: exit this MIDlet
     */
    public void commandAction(Command c, Displayable d) {
        if (c == cmdOK) {
            flipFlop();
        } else if (c == cmdExit) {
            destroyApp(false);
            notifyDestroyed();
        }
    }
}


20.2 System Properties

MIDP inherits the system property mechanism from CLDC (see Section 5.2.10, "Property Support"). In addition to the properties provided by the CLDC, the MIDP Specification defines the following additional properties that can be retrieved by calling the method java.lang.System.getProperty (see Table 20.1).

The microedition.locale property is a String that consists of the language, country code, and variant separated by "-" (Unicode U+002D), for example, "fr-FR" or "en-US". Note that this is different from the J2SE definition for Locale printed strings where fields are separated by "_" (Unicode U+005F).

Table 20.1. System properties defined by MIDP

System Property

Description

microedition.locale

The current locale of the device; may be null.

microedition.profiles

A blank (Unicode U+0020) separated list of the J2ME profiles that this device supports. For MIDP 2.0 devices, this property MUST contain at least "MIDP-2.0".

microedition.commports

A comma separated list of ports that can be combined with a "comm:" prefix as the URL string to be used to open a serial port connection (see Section 15.8, "CommConnection").

microedition.hostname

The local hostname (if available).

This locale string can be used by a MIDlet to determine the locale for which the underlying device is configured.

The microedition.profiles property can be used by a MIDlet to ensure that the underlying platform supports the necessary profile(s) and profile version(s) that the application requires.


20.3 Application Resource Files

MIDP provides the capability of storing resources in the application's JAR that can be accessed by a MIDlet at run time. An example of such a resource might be a locale bundle, an icon, or a graphical image; however, any thing that can be accessed as an InputStream can also be stored. These resources are accessed using the method getResourceAsStream(String name) of class java.lang.Class.

The rules and the parameter string format for accessing resources inside a JAR file have been discussed in Section 19.1.4, "MIDlet Suite Execution Environment." As a general rule, if the parameter string to the getResourceAsStream method begins with a '/', the search for the resource begins at the "root" of the JAR file; however, if it does not begin with a '/', the resource is searched for along a path relative to the class instance retrieving the resource.


20.4 Exiting a MIDlet

The CLDC Specification states that a call to the method java.lang.System.exit is effectively equivalent to calling the method Runtime.getRuntime().exit. This means that in a CLDC program, calling the System.exit method will exit the virtual machine. However, since MIDP defines its own application model, this behavior is not desirable. For instance, it is not desirable that a single MIDlet in a MIDlet suite, upon exiting, would shut down the entire virtual machine (and therefore shut down the other MIDlets as well.) Rather, a well-behaved MIDlet should exit by calling the destroyApp and notifyDestroyed methods.

In order to prevent MIDP applications from accidentally shutting down the entire virtual machine, the MIDP Specification redefines the behavior of the system.exit method. In MIDP, calling this method will always throw a java.lang.SecurityException.


Chapter 21. Summary

In the past few years, we have witnessed the beginning of an exciting new era in the history of computing. Wireless, handheld computing and communication devices, or mobile information devices (MIDs), have taken the role that desktop computers had earlier as the forefront of computing technology. As a result of this transition, computing and communication devices are becoming more and more mobile, personal, and ubiquitous. The number of mobile information devices has already surpassed the number of conventional personal computers, and this trend is likely to continue and strengthen in the future. The vast majority of people in the world will probably never use a traditional desktop computer. However, it is very likely that a very large percentage of them will eventually be using some kind of a mobile information device.

At the same time, the rapid emergence of the Internet is playing an increasingly visible role in the development and evolution of mobile information devices. People have become dependent on the information that is available on the Internet, and they will also want access to that information from mobile information devices. This will place much more emphasis on the ability to customize and personalize mobile information devices according to the needs of the individual users. Unlike in the past, when wireless devices typically came from the factory with a hard-coded feature set, the devices will become much more dependent on dynamically downloaded software. Consequently, there is a need for technologies that open up the mobile information devices for third-party software development, and make it possible to extend and customize the features of mobile information devices for Internet access and Internet-based services in a dynamic, secure fashion.

As discussed in this book, we believe that the Java™ programming language is ideally suited to become the standard application development language for wireless devices. After all, Java technology provides an unsurpassed combination of benefits for device manufacturers, wireless network operators, content providers, and individual application developers. These benefits include the dynamic delivery of interactive content, security, cross-platform compatibility, enhanced user experience, and the power of a modern object-oriented programming language with a very large established developer base.

In this book, we have summarized the recent advances in creating a portable, secure, small-footprint Java application development environment for small, connected devices. The initial work in this area started in early 1998 at Sun Microsystems Laboratories (Sun Labs) with the creation of a small, new Java execution engine, the K Virtual Machine (KVM). This work led to a number of collaborative research and development efforts with major consumer device manufacturers and other companies. Eventually, a number of standardization efforts were started to harmonize the key features and libraries across a wide variety of possible target devices.

This book has presented the overall architecture of Java™ 2 Platform, Micro Edition (J2ME™), focusing specifically on two key J2ME standards: Connected, Limited Device Configuration (CLDC) version 1.1 and Mobile Information Device Profile (MIDP) version 2.0. Connected, Limited Device Configuration is intended to serve as a generic, "lowest common denominator" platform or building block that targets all kinds of small, connected devices that have at least 192 kilobytes of memory available for the Java environment and applications. Mobile Information Device Profile builds on top of CLDC and adds valuable application programming interfaces for a specific category of devices: wireless, mobile, two-way communication devices such as cellular telephones and two-way pagers.

A key characteristic of the CLDC and MIDP standards is the incremental and complementary nature of the platforms that they define. A central goal in creating the CLDC and MIDP standards was to avoid any conflicts with existing wireless application technologies, such as i-Mode or Wireless Application Protocol (WAP), so that they complement the existing technologies rather than compete with them. In general, the application development environments defined by CLDC and MIDP can be added flexibly on top of the existing software and hardware solutions regardless of the target architecture or specific networking technology. Typically, the changes required to the existing system software stack are very small. This means that device manufacturers and network operators can continue taking advantage of their investments in the existing software, hardware, and networking infrastructure.

Both CLDC and MIDP standards were developed using Java Community Process (JCP), a process that encourages active and open collaboration among industry participants who share the same interests in developing new APIs for the Java platform. More than 60 companies participated directly in the CLDC and MIDP standardization efforts, and more than a thousand companies and individuals participated in these efforts indirectly by sending us feedback and comments on the various versions of the CLDCSpecification and MIDPSpecification. In that sense, these standards represent a truly collaborative effort among the key players in the wireless communication and device industry. They also reflect how much general interest there is in the mobile information device area today.

Both the CLDC and MIDP standards have been received extremely well by the device manufacturers, network operators, content providers, and individual application developers. As of early 2003, more than 70 million Java Powered™ devices have already been shipped, and the number is likely to grow rapidly to hundreds of millions of devices in the next few years. Development tools for the Java 2 Platform, Micro Edition are also readily available from major tool vendors such as Borland and Metrowerks.

In summary, we believe that the transition to Internet-enabled, wireless, mobile information devices will fundamentally alter the landscape of computing and communication devices and services. This book has presented the J2ME CLDC 1.1 and MIDP 2.0 standards that define powerful, portable, secure, small-footprint application development environments in order to bring Java technology to mobile information devices. We hope that this book, for its part, encourages people to use these technologies and continue the work in this exciting new area.


References

[reference 1] User Datagram Protocol. The Internet Engineering Task Force. August 1980. <http://www.ietf.org/rfc/rfc768.txt>

[reference 2] Renumbering Needs Work. The Internet Engineering Task Force. February 1996. <http://www.ietf.org/rfc/rfc1900.txt>

[reference 3] Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies. The Internet Engineering Task Force. November 1996. <http://www.ietf.org/rfc/rfc2045.txt>

[reference 4] The TLS Protocol Version 1.0. The Internet Engineering Task Force. January 1999. <http://www.ietf.org/rfc/rfc2246.txt>

[reference 5] Uniform Resource Identifiers (URI): Generic Syntax. The Internet Engineering Task Force. August 1998. <http://www.ietf.org/rfc/rfc2396.txt>

[reference 6] PKCS #1: RSA Cryptography Specifications Version 2.0. The Internet Engineering Task Force. October 1998. <http://www.ietf.org/rfc/rfc2437.txt>

[reference 7] Internet X.509 Public Key Infrastructure Certificate and CRL Profile. The Internet Engineering Task Force. January 1999. <http://www.ietf.org/rfc/rfc2459.txt>

[reference 8] X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP. The Internet Engineering Task Force. June 1999. <http://www.ietf.org/rfc/rfc2560.txt>

[reference 9] Hypertext Transfer Protocol — HTTP/1.1. The Internet Engineering Task Force. June 1999. <http://www.ietf.org/rfc/rfc2616.txt>

[reference 10] HTTP Authentication: Basic and Digest Access Authentication. The Internet Engineering Task Force. June 1999. <http://www.ietf.org/rfc/rfc2617.txt>

[reference 11] HTTP Over TLS. The Internet Engineering Task Force. May 2000. <http://www.ietf.org/rfc/rfc2818.txt>

[reference 12] Freier, Alan O., Philip Karlton, Paul C. Kocher. The SSL Protocol Version 3.0. November 1996 <http://home.netscape.com/eng/ssl3/draft302.txt>

[reference 13] Wireless Application Protocol Wireless Transport Layer Security Specification. Open Mobile Alliance WAP Forum Specifications June 2000 (WAP 1.2.1) conformance release. June 2000. <http://www.wapforum.org/what/technical_1_2_1.htm>

[reference 14] WAP TLS Profile and Tunneling Specification, WAP-219-TLS. Open Mobile Alliance WAP Forum Releases. April 2001. <http://www.wapforum.org/what/technical.htm>

[reference 15] WAP Certificate and CRL Profiles WAP-211-WAPCert. Open Mobile Alliance WAP Forum Releases. May 2001. <http://www.wapforum.org/what/technical.htm>


Appendix A. CLDC Application Programming Interface

This appendix contains the application programming interface documentation in Almanac format for the CLDC. For a description of this format, refer to "Almanac Legend" on page 356.

Full CLDC javadocs with detailed comments are available in the CLDC Specification (see "Related Literature and Helpful Web Pages" on page xxv) or as part of the CLDC reference implementation software that can be downloaded from Sun's web site (http://www.sun.com/software/communitysource/j2me/cldc/).


Almanac Legend

The Almanac format presents all classes and interfaces in alphabetic order. Each class displays a list of its members in alphabetic order, mixing fields, methods, and constructors together.

The Almanac format used in this book is modeled after the style introduced by Patrick Chan in his excellent book, JavaTM Developers Almanac.

  1. The name of the class or interface. If the name refers to an interface, its name is printed in italics.

  2. The name of the package containing the class or interface.

  3. The inheritance chain of superclasses. A class is a subclass of the one above it. Inheritance hierarchies for interfaces are not displayed, because interfaces can potentially inherit multiple superinterfaces.

  4. The names of the interfaces implemented by the class to its left on the same line.

  5. Icons that indicate modifiers or members. If the "protected" symbol does not appear, the member is public. Private and package-private members have no symbols and are not shown.

    abstract

    • final

    static

    static final

    protected

    constructor

    field

  6. The return type of a method or the declared type of a field. It is blank for constructors.

  7. The name of the member. Members are sorted alphabetically. If it is a method, the parameter list and optional throws clause follows.


CLDC Almanac

ArithmeticException

java.lang

[View full width]
Object
      Throwable
         Exception
            RuntimeException
               ArithmeticException

                           ArithmeticException()
                           ArithmeticException(String s)

ArrayIndexOutOfBoundsException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IndexOutOfBoundsException
                    ArrayIndexOutOfBoundsException

                            ArrayIndexOutOfBoundsException()
                            ArrayIndexOutOfBoundsException(int index)
                            ArrayIndexOutOfBoundsException(String s)

ArrayStoreException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                ArrayStoreException

                            ArrayStoreException()
                            ArrayStoreException(String s)

Boolean

java.lang

[View full width]
Object
      Boolean

                                Boolean(boolean value)
                       boolean booleanValue()
                       boolean equals(Object obj)
CLDC 1.1                Boolean FALSE
                           int hashCode()
                        String toString()
CLDC 1.1                Boolean TRUE

Byte

java.lang

[View full width]
Object
      Byte

                                Byte(byte value)
                          byte byteValue()
                       boolean equals(Object obj)
                           int hashCode()
                           byte MAX_VALUE
                           byte MIN_VALUE
                           byte parseByte(String s) throws NumberFormatException
                           byte parseByte(String s, int radix) throws NumberFormatException
                        String toString()

ByteArrayInputStream

java.io

[View full width]
Object
      InputStream
          ByteArrayInputStream

                          int available()
                        byte[] buf
                               ByteArrayInputStream(byte[] buf)
                               ByteArrayInputStream(byte[] buf, int offset, int length)
                         void close() throws IOException
                           int count
                           int mark
                         void mark(int readAheadLimit)
                      boolean markSupported()
                           int pos
                          int read()
                          int read(byte[] b, int off, int len)
                         void reset()
                         long skip(long n)

ByteArrayOutputStream

java.io

[View full width]
Object
      OutputStream
         ByteArrayOutputStream

                          byte[] buf
                                ByteArrayOutputStream()
                                ByteArrayOutputStream(int size)
                          void close() throws IOException
                            int count
                          void reset()
                           int size()
                        byte[] toByteArray()
                        String toString()
                          void write(byte[] b, int off, int len)
                          void write(int b)

Calendar

java.util

[View full width]
Object
      Calendar

                        boolean after(Object when)
                             int AM
                             int AM_PM
                             int APRIL
                             int AUGUST
                        boolean before(Object when)
                                  Calendar()
CLDC 1.1                    void computeFields()
CLDC 1.1                    void computeTime()
                             int DATE
                             int DAY_OF_MONTH
                             int DAY_OF_WEEK
                             int DECEMBER
                        boolean equals(Object obj)
                             int FEBRUARY
CLDC 1.1                   int[] fields
                             int FRIDAY
                            int get(int field)
                       Calendar getInstance()
                       Calendar getInstance(TimeZone zone)
                           Date getTime()
                           long getTimeInMillis()
                      TimeZone getTimeZone()
                            int HOUR
                            int HOUR_OF_DAY
CLDC 1.1              boolean[] isSet
                            int JANUARY
                            int JULY
                            int JUNE
                            int MARCH
                            int MAY
                            int MILLISECOND
                            int MINUTE
                            int MONDAY
                            int MONTH
                            int NOVEMBER
                            int OCTOBER
                            int PM
                            int SATURDAY
                            int SECOND
                            int SEPTEMBER
                          void set(int field, int value)
                          void setTime(Date date)
                           void setTimeInMillis(long millis)
                          void setTimeZone(TimeZone value)
                            int SUNDAY
                            int THURSDAY
CLDC 1.1                   long time
                            int TUESDAY
                            int WEDNESDAY
                            int YEAR

Character

java.lang

[View full width]
Object
      Character

                               Character(char value)
                          char charValue()
                           int digit(char ch, int radix)
                       boolean equals(Object obj)
                           int hashCode()
                       boolean isDigit(char ch)
                       boolean isLowerCase(char ch)
                       boolean isUpperCase(char ch)
                           int MAX_RADIX
                          char MAX_VALUE
                           int MIN_RADIX
                         char MIN_VALUE
                          char toLowerCase(char ch)
                            String toString()
                          char toUpperCase(char ch)

Class

java.lang

[View full width]
Object
      Class

                          Class forName(String className) throws ClassNotFoundException
                        String getName()
           java.io.InputStream getResourceAsStream(String name)
                       boolean isArray()
                       boolean isAssignableFrom(Class cls)
                       boolean isInstance(Object obj)
                       boolean isInterface()
                        Object newInstance() throws InstantiationException, IllegalAccessException
                        String toString()

ClassCastException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                ClassCastException

                           ClassCastException()
                           ClassCastException(String s)

ClassNotFoundException

java.lang

[View full width]
Object
      Throwable
          Exception
             ClassNotFoundException

                           ClassNotFoundException()
                           ClassNotFoundException(String s)

Connection

javax.microedition.io

Connection

                     void close() throws java.io.IOException

ConnectionNotFoundException

javax.microedition.io

[View full width]
Object
      Throwable
          Exception
             java.io.IOException
                 ConnectionNotFoundException

                           ConnectionNotFoundException()
                           ConnectionNotFoundException(String s)

Connector

javax.microedition.io

[View full width]
Object
      Connector

                    Connection open(String name) throws java.io.IOException
                    Connection open(String name, int mode) throws java.io.IOException
                    Connection open(String name, int mode, boolean timeouts) throws java.io.IOException
       java.io.DataInputStream openDataInputStream(String name) throws java.io.IOException
      java.io.DataOutputStream openDataOutputStream(String name) throws java.io.IOException
           java.io.InputStream openInputStream(String name) throws java.io.IOException
          java.io.OutputStream openOutputStream(String name) throws java.io.IOException
                            int READ
                            int READ_WRITE
                            int WRITE

ContentConnection

javax.microedition.io

ContentConnection                         StreamConnection

                     String getEncoding()
                       long getLength()
                     String getType()

Datagram

javax.microedition.io

Datagram       java.io.DataInput, java.io.DataOutput

                   String getAddress()
                   byte[] getData()
                      int getLength()
                      int getOffset()
                     void reset()
                     void setAddress(Datagram reference)
                     void setAddress(String addr) throws java.io.IOException
                     void setData(byte[] buffer, int offset, int len)
                     void setLength(int len)

DatagramConnection

javax.microedition.io

DatagramConnection                       Connection

                       int getMaximumLength() throws java.io.IOException
                       int getNominalLength() throws java.io.IOException
                  Datagram newDatagram(byte[] buf, int size) throws java.io.IOException
                  Datagram newDatagram(byte[] buf, int size, String addr) throws java.io.IOException
                  Datagram newDatagram(int size) throws java.io.IOException
                  Datagram newDatagram(int size, String addr) throws java.io.IOException
                      void receive(Datagram dgram) throws java.io.IOException
                      void send(Datagram dgram) throws java.io.IOException

DataInput

java.io

DataInput

                       boolean readBoolean() throws IOException
                          byte readByte() throws IOException
                          char readChar() throws IOException
CLDC 1.1                double readDouble() throws IOException
CLDC 1.1                 float readFloat() throws IOException
                          void readFully(byte[] b) throws IOException
                          void readFully(byte[] b, int off, int len) throws IOException
                           int readInt() throws IOException
                          long readLong() throws IOException
                         short readShort() throws IOException
                           int readUnsignedByte() throws IOException
                           int readUnsignedShort() throws IOException
                        String readUTF() throws IOException
                           int skipBytes(int n) throws IOException

DataInputStream

java.io

[View full width]
Object
      InputStream
          DataInputStream                       DataInput

                         int available() throws IOException
                        void close() throws IOException
                                DataInputStream(InputStream in)
                   InputStream in
                         void mark(int readlimit)
                      boolean markSupported()
                           int read() throws IOException
                           int read(byte[] b) throws IOException
                           int read(byte[] b, int off, int len) throws IOException
                       boolean readBoolean() throws IOException
                          byte readByte() throws IOException
                          char readChar() throws IOException
CLDC 1.1                double readDouble() throws IOException
CLDC 1.1                 float readFloat() throws IOException
                          void readFully(byte[] b) throws IOException
                          void readFully(byte[] b, int off, int len) throws IOException
                           int readInt() throws IOException
                          long readLong() throws IOException
                         short readShort() throws IOException
                           int readUnsignedByte() throws IOException
                           int readUnsignedShort() throws IOException
                        String readUTF() throws IOException
                        String readUTF(DataInput in) throws IOException
                         void reset() throws IOException
                         long skip(long n) throws IOException
                          int skipBytes(int n) throws IOException

DataOutput

java.io

DataOutput

                          void write(byte[] b) throws IOException
                          void write(byte[] b, int off, int len) throws IOException
                          void write(int b) throws IOException
                          void writeBoolean(boolean v) throws IOException
                          void writeByte(int v) throws IOException
                          void writeChar(int v) throws IOException
                          void writeChars(String s) throws IOException
CLDC 1.1                  void writeDouble(double v) throws IOException
CLDC 1.1                  void writeFloat(float v) throws IOException
                          void writeInt(int v) throws IOException
                          void writeLong(long v) throws IOException
                          void writeShort(int v) throws IOException
                          void writeUTF(String s) throws IOException

DataOutputStream

java.io

[View full width]
Object
      OutputStream
         DataOutputStream                    DataOutput

                       void close() throws IOException
                             DataOutputStream(OutputStream out)
                       void flush() throws IOException
                 OutputStream out
                       void write(byte[] b, int off, int len) throws IOException
                       void write(int b) throws IOException
                        void writeBoolean(boolean v) throws IOException
                        void writeByte(int v) throws IOException
                        void writeChar(int v) throws IOException
                        void writeChars(String s) throws IOException
CLDC 1.1                void writeDouble(double v) throws IOException
CLDC 1.1                void writeFloat(float v) throws IOException
                        void writeInt(int v) throws IOException
                        void writeLong(long v) throws IOException
                        void writeShort(int v) throws IOException
                        void writeUTF(String str) throws IOException

Date

java.util

[View full width]
Object
      Date

                                Date()
                                Date(long date)
                       boolean equals(Object obj)
                          long getTime()
                           int hashCode()
                          void setTime(long time)
CLDC 1.1                String toString()

Double

java.lang

[View full width]
         Object
CLDC 1.1       Double

CLDC 1.1                  byte byteValue()
CLDC 1.1                        Double(double value)
CLDC 1.1                  long doubleToLongBits(double value)
CLDC 1.1                double doubleValue()
CLDC 1.1               boolean equals(Object obj)
CLDC 1.1                 float floatValue()
CLDC 1.1                   int hashCode()
CLDC 1.1                   int intValue()
CLDC 1.1               boolean isInfinite()
CLDC 1.1               boolean isInfinite(double v)
CLDC 1.1               boolean isNaN()
CLDC 1.1               boolean isNaN(double v)
CLDC 1.1                 double longBitsToDouble(long bits)
CLDC 1.1                  long longValue()
CLDC 1.1                 double MAX_VALUE
CLDC 1.1                 double MIN_VALUE
CLDC 1.1                 double NaN
CLDC 1.1                 double NEGATIVE_INFINITY
CLDC 1.1                 double parseDouble(String s) throws NumberFormatException
CLDC 1.1                 double POSITIVE_INFINITY
CLDC 1.1                 short shortValue()
CLDC 1.1                String toString()
CLDC 1.1                 String toString(double d)
CLDC 1.1                 Double valueOf(String s) throws NumberFormatException

EmptyStackException

java.util

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                EmptyStackException

                            EmptyStackException()

Enumeration

java.util

Enumeration

                       boolean hasMoreElements()
                        Object nextElement()

EOFException

java.io

[View full width]
Object
      Throwable
          Exception
             IOException
                EOFException

                             EOFException()
                             EOFException(String s)

Error

java.lang

[View full width]
Object
      Throwable
          Error

                                Error()
                                Error(String s)

Exception

java.lang

[View full width]
Object
      Throwable
          Exception

                                Exception()
                                Exception(String s)

Float

java.lang

[View full width]
        Object
CLDC 1.1      Float

CLDC 1.1                  byte byteValue()
CLDC 1.1                double doubleValue()
CLDC 1.1               boolean equals(Object obj)
CLDC 1.1                        Float(double value)
CLDC 1.1                        Float(float value)
CLDC 1.1                    int floatToIntBits(float value)
CLDC 1.1                float floatValue()
CLDC 1.1                  int hashCode()
CLDC 1.1                  float intBitsToFloat(int bits)
CLDC 1.1                   int intValue()
CLDC 1.1               boolean isInfinite()
CLDC 1.1                 boolean isInfinite(float v)
CLDC 1.1              boolean isNaN()
CLDC 1.1                boolean isNaN(float v)
CLDC 1.1                 long longValue()
CLDC 1.1                  float MAX_VALUE
CLDC 1.1                   float MIN_VALUE
CLDC 1.1                   float NaN
CLDC 1.1                   float NEGATIVE_INFINITY
CLDC 1.1                   float parseFloat(String s) throws NumberFormatException
CLDC 1.1                   float POSITIVE_INFINITY
CLDC 1.1                 short shortValue()
CLDC 1.1                String toString()
CLDC 1.1                String toString(float f)
CLDC 1.1                  Float valueOf(String s) throws NumberFormatException

Hashtable

java.util

[View full width]
Object
      Hashtable

                          void clear()
                       boolean contains(Object value)
                       boolean containsKey(Object key)
                   Enumeration elements()
                        Object get(Object key)
                                Hashtable()
                                Hashtable(int initialCapacity)
                       boolean isEmpty()
                   Enumeration keys()
                        Object put(Object key, Object value)
                           void rehash()
                        Object remove(Object key)
                           int size()
                        String toString()

IllegalAccessException

java.lang

[View full width]
Object
      Throwable
          Exception
             IllegalAccessException

                               IllegalAccessException()
                               IllegalAccessException(String s)

IllegalArgumentException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IllegalArgumentException

                            IllegalArgumentException()
                            IllegalArgumentException(String s)

IllegalMonitorStateException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IllegalMonitorStateException

                             IllegalMonitorStateException()
                             IllegalMonitorStateException(String s)

IllegalThreadStateException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IllegalArgumentException
                     IllegalThreadStateException

                             IllegalThreadStateException()
                             IllegalThreadStateException(String s)

IndexOutOfBoundsException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                 IndexOutOfBoundsException

                            IndexOutOfBoundsException()
                            IndexOutOfBoundsException(String s)

InputConnection

javax.microedition.io

InputConnection                                Connection

        java.io.DataInputStream openDataInputStream() throws java.io.IOException
            java.io.InputStream openInputStream() throws java.io.IOException

InputStream

java.io

[View full width]
Object
      InputStream

                           int available() throws IOException
                          void close() throws IOException
                                InputStream()
                          void mark(int readlimit)
                       boolean markSupported()
                           int read() throws IOException
                           int read(byte[] b) throws IOException
                           int read(byte[] b, int off, int len) throws IOException
                          void reset() throws IOException
                          long skip(long n) throws IOException

InputStreamReader

java.io

[View full width]
Object
      Reader
         InputStreamReader

                          void close() throws IOException
                               InputStreamReader(InputStream is)
                               InputStreamReader(InputStream is, String enc) throws UnsupportedEncodingException
                          void mark(int readAheadLimit) throws IOException
                       boolean markSupported()
                           int read() throws IOException
                           int read(char[] cbuf, int off, int len) throws IOException
                       boolean ready() throws IOException
                          void reset() throws IOException
                          long skip(long n) throws IOException

InstantiationException

java.lang

[View full width]
Object
      Throwable
          Exception
             InstantiationException

                                InstantiationException()
                                InstantiationException(String s)

Integer

java.lang

[View full width]
Object
      Integer

                          byte byteValue()
CLDC 1.1                double doubleValue()
                       boolean equals(Object obj)
CLDC 1.1                 float floatValue()
                           int hashCode()
                               Integer(int value)
                           int intValue()
                          long longValue()
                            int MAX_VALUE
                            int MIN_VALUE
                            int parseInt(String s) throws NumberFormatException
                            int parseInt(String s, int radix) throws NumberFormatException
                          short shortValue()
                         String toBinaryString(int i)
                         String toHexString(int i)
                         String toOctalString(int i)
                         String toString()
                         String toString(int i)
                         String toString(int i, int radix)
                        Integer valueOf(String s) throws NumberFormatException
                        Integer valueOf(String s, int radix) throws NumberFormatException

InterruptedException

java.lang

[View full width]
Object
      Throwable
          Exception
             InterruptedException

                               InterruptedException()
                               InterruptedException(String s)

InterruptedIOException

java.io

[View full width]
Object
      Throwable
          Exception
             IOException
                InterruptedIOException

                           int bytesTransferred
                               InterruptedIOException()
                               InterruptedIOException(String s)

IOException

java.io

[View full width]
Object
      Throwable
          Exception
             IOException

                                IOException()
                                IOException(String s)

Long

java.lang

[View full width]
Object
      Long

CLDC 1.1                double doubleValue()
                       boolean equals(Object obj)
CLDC 1.1                 float floatValue()
                           int hashCode()
                                Long(long value)
                          long longValue()
                           long MAX_VALUE
                           long MIN_VALUE
                          long parseLong(String s) throws NumberFormatException
                          long parseLong(String s, int radix) throws NumberFormatException
                        String toString()
                        String toString(long i)
                        String toString(long i, int radix)

Math

java.lang

[View full width]
Object
      Math

CLDC 1.1                 double abs(double a)
CLDC 1.1                  float abs(float a)
                            int abs(int a)
                           long abs(long a)
CLDC 1.1                 double ceil(double a)
CLDC 1.1                 double cos(double a)
CLDC 1.1                 double E
CLDC 1.1                 double floor(double a)
CLDC 1.1                 double max(double a, double b)
CLDC 1.1                  float max(float a, float b)
                            int max(int a, int b)
                           long max(long a, long b)
CLDC 1.1                 double min(double a, double b)
CLDC 1.1                  float min(float a, float b)
                            int min(int a, int b)
                           long min(long a, long b)
CLDC 1.1                 double PI
CLDC 1.1                 double sin(double a)
CLDC 1.1                 double sqrt(double a)
CLDC 1.1                 double tan(double a)
CLDC 1.1                 double toDegrees(double angrad)
CLDC 1.1                 double toRadians(double angdeg)

NegativeArraySizeException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                 NegativeArraySizeException

                               NegativeArraySizeException()
                               NegativeArraySizeException(String s)

NoClassDefFoundError

java.lang

[View full width]
Object
      Throwable
          Error
CLDC 1.1      NoClassDefFoundError

CLDC 1.1                      NoClassDefFoundError()
CLDC 1.1                      NoClassDefFoundError(String s)

NoSuchElementException

java.util

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                NoSuchElementException

                           NoSuchElementException()
                           NoSuchElementException(String s)

NullPointerException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                NullPointerException

                              NullPointerException()
                              NullPointerException(String s)

NumberFormatException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IllegalArgumentException
                     NumberFormatException

                             NumberFormatException()
                             NumberFormatException(String s)

Object

java.lang

Object

                        boolean equals(Object obj)
                          Class getClass()
                            int hashCode()
                            void notify()
                            void notifyAll()
                                 Object()
                         String toString()
                            void wait() throws InterruptedException
                            void wait(long timeout) throws InterruptedException
                            void wait(long timeout, int nanos) throws InterruptedException

OutOfMemoryError

java.lang

[View full width]
Object
      Throwable
          Error
              VirtualMachineError
                   OutOfMemoryError

                             OutOfMemoryError()
                             OutOfMemoryError(String s)

OutputConnection

javax.microedition.io

OutputConnection                               Connection

         java.io.DataOutputStream openDataOutputStream() throws java.io.IOException
             java.io.OutputStream openOutputStream() throws java.io.IOException

OutputStream

java.io

[View full width]
Object
      OutputStream

                          void close() throws IOException
                          void flush() throws IOException
                                OutputStream()
                          void write(byte[] b) throws IOException
                          void write(byte[] b, int off, int len) throws IOException
                          void write(int b) throws IOException

OutputStreamWriter

java.io

[View full width]
Object
      Writer
          OutputStreamWriter

                          void close() throws IOException
                          void flush() throws IOException
                                OutputStreamWriter(OutputStream os)
                                OutputStreamWriter(OutputStream os, String enc) throws UnsupportedEncodingException
                          void write(char[] cbuf, int off, int len) throws IOException
                          void write(int c) throws IOException
                          void write(String str, int off, int len) throws IOException

PrintStream

java.io

[View full width]
Object
      OutputStream
         PrintStream

                       boolean checkError()
                          void close()
                          void flush()
                          void print(boolean b)
                          void print(char c)
                          void print(char[] s)
CLDC 1.1                  void print(double d)
CLDC 1.1                  void print(float f)
                          void print(int i)
                          void print(long l)
                          void print(Object obj)
                          void print(String s)
                          void println()
                          void println(boolean x)
                          void println(char x)
                          void println(char[] x)
CLDC 1.1                  void println(double x)
CLDC 1.1                  void println(float x)
                          void println(int x)
                          void println(long x)
                          void println(Object x)
                          void println(String x)
                                PrintStream(OutputStream out)
                           void setError()
                          void write(byte[] buf, int off, int len)
                          void write(int b)

Random

java.util

[View full width]
Object
      Random

                            int next(int bits)
CLDC 1.1                double nextDouble()
CLDC 1.1                 float nextFloat()
                           int nextInt()
CLDC 1.1                   int nextInt(int n)
                          long nextLong()
                                Random()
                                Random(long seed)
                          void setSeed(long seed)

Reader

java.io

[View full width]
Object
      Reader

                           void close() throws IOException
                          Object lock
                          void mark(int readAheadLimit) throws IOException
                       boolean markSupported()
                           int read() throws IOException
                           int read(char[] cbuf) throws IOException
                           int read(char[] cbuf, int off, int len) throws IOException
                                 Reader()
                                 Reader(Object lock)
                       boolean ready() throws IOException
                          void reset() throws IOException
                          long skip(long n) throws IOException

Reference

java.lang.ref

[View full width]
        Object
CLDC 1.1      Reference

CLDC 1.1                  void clear()
CLDC 1.1                Object get()

Runnable

java.lang

Runnable

                          void run()

Runtime

java.lang

[View full width]
Object
      Runtime

                          void exit(int status)
                          long freeMemory()
                          void gc()
                       Runtime getRuntime()
                          long totalMemory()

RuntimeException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException

                            RuntimeException()
                            RuntimeException(String s)

SecurityException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                SecurityException

                            SecurityException()
                            SecurityException(String s)

Short

java.lang

[View full width]
Object
      Short

                        boolean equals(Object obj)
                            int hashCode()
                           short MAX_VALUE
                           short MIN_VALUE
                           short parseShort(String s) throws NumberFormatException
                           short parseShort(String s, int radix) throws NumberFormatException
                                 Short(short value)
                          short shortValue()
                         String toString()

Stack

java.util

[View full width]
Object
      Vector
         Stack

                       boolean empty()
                        Object peek()
                        Object pop()
                        Object push(Object item)
                           int search(Object o)
                                Stack()

StreamConnection

javax.microedition.io

StreamConnection InputConnection, OutputConnection

StreamConnectionNotifier

javax.microedition.io

StreamConnectionNotifier                       Connection

              StreamConnection acceptAndOpen() throws java.io.IOException

String

java.lang

[View full width]
Object
      String

                          char charAt(int index)
                           int compareTo(String anotherString)
                        String concat(String str)
                       boolean endsWith(String suffix)
                       boolean equals(Object anObject)
CLDC 1.1               boolean equalsIgnoreCase(String anotherString)
                        byte[] getBytes()
                        byte[] getBytes(String enc) throws java.io.UnsupportedEncodingException
                          void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
                           int hashCode()
                           int indexOf(int ch)
                           int indexOf(int ch, int fromIndex)
                           int indexOf(String str)
                           int indexOf(String str, int fromIndex)
CLDC 1.1                String intern()
                           int lastIndexOf(int ch)
                           int lastIndexOf(int ch, int fromIndex)
                           int length()
                       boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
                        String replace(char oldChar, char newChar)
                       boolean startsWith(String prefix)
                       boolean startsWith(String prefix, int toffset)
                                String()
                                String(byte[] bytes)
                                String(byte[] bytes, int off, int len)
                                String(byte[] bytes, int off, int len, String enc) throws java.io.UnsupportedEncodingException
                                String(byte[] bytes, String enc) throws java.io.UnsupportedEncodingException
                                String(char[] value)
                                String(char[] value, int offset, int count)
                                String(String value)
                                String(StringBuffer buffer)
                        String substring(int beginIndex)
                        String substring(int beginIndex, int endIndex)
                        char[] toCharArray()
                        String toLowerCase()
                        String toString()
                        String toUpperCase()
                        String trim()
                         String valueOf(boolean b)
                         String valueOf(char c)
                         String valueOf(char[] data)
                         String valueOf(char[] data, int offset, int count)
CLDC 1.1                 String valueOf(double d)
CLDC 1.1                 String valueOf(float f)
                         String valueOf(int i)
                         String valueOf(long l)
                         String valueOf(Object obj)

StringBuffer

java.lang

[View full width]
Object
      StringBuffer

                  StringBuffer append(boolean b)
                  StringBuffer append(char c)
                  StringBuffer append(char[] str)
                  StringBuffer append(char[] str, int offset, int len)
CLDC 1.1          StringBuffer append(double d)
CLDC 1.1          StringBuffer append(float f)
                  StringBuffer append(int i)
                  StringBuffer append(long l)
                  StringBuffer append(Object obj)
                  StringBuffer append(String str)
                           int capacity()
                          char charAt(int index)
                  StringBuffer delete(int start, int end)
                  StringBuffer deleteCharAt(int index)
                          void ensureCapacity(int minimumCapacity)
                          void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
                  StringBuffer insert(int offset, boolean b)
                  StringBuffer insert(int offset, char c)
                  StringBuffer insert(int offset, char[] str)
CLDC 1.1          StringBuffer insert(int offset, double d)
CLDC 1.1          StringBuffer insert(int offset, float f)
                  StringBuffer insert(int offset, int i)
                  StringBuffer insert(int offset, long l)
                  StringBuffer insert(int offset, Object obj)
                  StringBuffer insert(int offset, String str)
                           int length()
                  StringBuffer reverse()
                          void setCharAt(int index, char ch)
                          void setLength(int newLength)
                                StringBuffer()
                                StringBuffer(int length)
                                StringBuffer(String str)
                        String toString()

StringIndexOutOfBoundsException

java.lang

[View full width]
Object
      Throwable
          Exception
             RuntimeException
                IndexOutOfBoundsException
                    StringIndexOutOfBoundsException

                               StringIndexOutOfBoundsException()
                               StringIndexOutOfBoundsException(int index)
                               StringIndexOutOfBoundsException(String s)

System

java.lang

[View full width]
Object
      System

                           void arraycopy(Object src, int srcOffset, Object dst, int dstOffset, int length)
                           long currentTimeMillis()
            java.io.PrintStream err
                           void exit(int status)
                           void gc()
                         String getProperty(String key)
                            int identityHashCode(Object x)
            java.io.PrintStream out

Thread

java.lang

[View full width]
Object
      Thread                                 Runnable

                            int activeCount()
                         Thread currentThread()
CLDC 1.1                 String getName()
                            int getPriority()
CLDC 1.1                  void interrupt()
                        boolean isAlive()
                           void join() throws InterruptedException
                             int MAX_PRIORITY
                             int MIN_PRIORITY
                             int NORM_PRIORITY
                           void run()
                          void setPriority(int newPriority)
                          void sleep(long millis) throws InterruptedException
                           void start()
                                 Thread()
                                 Thread(Runnable target)
CLDC 1.1                         Thread(Runnable target, String name)
CLDC 1.1                         Thread(String name)
                         String toString()
                            void yield()

Throwable

java.lang

[View full width]
Object
      Throwable

                        String getMessage()
                          void printStackTrace()
                               Throwable()
                               Throwable(String message)
                        String toString()

TimeZone

java.util

[View full width]
Object
      TimeZone

                       String[] getAvailableIDs()
                       TimeZone getDefault()
                        String getID()
                            int getOffset(int era, int year, int month, int day, int dayOfWeek, int millis)
                            int getRawOffset()
                       TimeZone getTimeZone(String ID)
                                TimeZone()
                        boolean useDaylightTime()

UnsupportedEncodingException

java.io

[View full width]
Object
      Throwable
          Exception
             IOException
                UnsupportedEncodingException

                           UnsupportedEncodingException()
                           UnsupportedEncodingException(String s)

UTFDataFormatException

java.io

[View full width]
Object
      Throwable
          Exception
             IOException
                UTFDataFormatException

                          UTFDataFormatException()
                          UTFDataFormatException(String s)

Vector

java.util

[View full width]
Object
      Vector

                          void addElement(Object obj)
                           int capacity()
                             int capacityIncrement
                       boolean contains(Object elem)
                          void copyInto(Object anArray)
                        Object elementAt(int index)
                             int elementCount
                         Object[] elementData
                   Enumeration elements()
                          void ensureCapacity(int minCapacity)
                        Object firstElement()
                           int indexOf(Object elem)
                           int indexOf(Object elem, int index)
                          void insertElementAt(Object obj, int index)
                       boolean isEmpty()
                        Object lastElement()
                           int lastIndexOf(Object elem)
                           int lastIndexOf(Object elem, int index)
                          void removeAllElements()
                       boolean removeElement(Object obj)
                          void removeElementAt(int index)
                          void setElementAt(Object obj, int index)
                          void setSize(int newSize)
                           int size()
                        String toString()
                          void trimToSize()
                                Vector()
                                Vector(int initialCapacity)
                                Vector(int initialCapacity, int capacityIncrement)

VirtualMachineError

java.lang

[View full width]
Object
      Throwable
          Error
              VirtualMachineError

                                VirtualMachineError()
                                VirtualMachineError(String s)

WeakReference

java.lang.ref

[View full width]
    Object
          Reference
CLDC 1.1     WeakReference

CLDC 1.1                        WeakReference(Object ref)

Writer

java.io

[View full width]
Object
      Writer

                          void close() throws IOException
                          void flush() throws IOException
                        Object lock
                          void write(char[] cbuf) throws IOException
                          void write(char[] cbuf, int off, int len) throws IOException
                          void write(int c) throws IOException
                          void write(String str) throws IOException
                          void write(String str, int off, int len) throws IOException
                                 Writer()
                                 Writer(Object lock)


Appendix B. MIDP Application Programming Interface

This appendix contains the application programming interface documentation in Almanac format for the MIDP. For a description of this format, refer to "Almanac Legend" on page 356.

Full MIDP javadocs with detailed comments are available in the MIDP Specification (see "Related Literature and Helpful Web Pages" on page xxv) or as part of the MIDP reference implementation software that can be downloaded from Sun's web site (http://www.sun.com/software/communitysource/j2me/midp/).


MIDP Almanac

Alert

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Screen
              Alert

                          void addCommand(Command cmd)
                                Alert(String title)
                                Alert(String title, String alertText, Image alertImage, AlertType alertType)
MIDP 2.0                Command DISMISS_COMMAND
                            int FOREVER
                           int getDefaultTimeout()
                         Image getImage()
MIDP 2.0                 Gauge getIndicator()
                        String getString()
                           int getTimeout()
                     AlertType getType()
                          void removeCommand(Command cmd)
                          void setCommandListener(CommandListener l)
                          void setImage(Image img)
MIDP 2.0                  void setIndicator(Gauge indicator)
                          void setString(String str)
                          void setTimeout(int time)
                          void setType(AlertType type)

AlertType

javax.microedition.lcdui

[View full width]
Object
      AlertType

                       AlertType ALARM
                                  AlertType()
                      AlertType CONFIRMATION
                      AlertType ERROR
                      AlertType INFO
                       boolean playSound(Display display)
                      AlertType WARNING

Canvas

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Canvas

                                Canvas()
                            int DOWN
                            int FIRE
                            int GAME_A
                            int GAME_B
                            int GAME_C
                            int GAME_D
                           int getGameAction(int keyCode)
                           int getHeight()
                           int getKeyCode(int gameAction)
                        String getKeyName(int keyCode)
                           Int getWidth()
                       boolean hasPointerEvents()
                       boolean hasPointerMotionEvents()
                       boolean hasRepeatEvents()
                           void hideNotify()
                       boolean isDoubleBuffered()
                            int KEY_NUM0
                            int KEY_NUM1
                            int KEY_NUM2
                            int KEY_NUM3
                            int KEY_NUM4
                            int KEY_NUM5
                            int KEY_NUM6
                            int KEY_NUM7
                            int KEY_NUM8
                            int KEY_NUM9
                            int KEY_POUND
                            int KEY_STAR
                           void keyPressed(int keyCode)
                           void keyReleased(int keyCode)
                           void keyRepeated(int keyCode)
                             int LEFT
                           void paint(Graphics g)
                           void pointerDragged(int x, int y)
                           void pointerPressed(int x, int y)
                           void pointerReleased(int x, int y)
                          void repaint()
                          void repaint(int x, int y, int width, int height)
                             int RIGHT
                           void serviceRepaints()
MIDP 2.0                   void setFullScreenMode(boolean mode)
                            void showNotify()
MIDP 2.0                    void sizeChanged(int w, int h)
                            int UP

Certificate

javax.microedition.pki

MIDP 2.0    Certificate

MIDP 2.0                String getIssuer()
MIDP 2.0                  long getNotAfter()
MIDP 2.0                  long getNotBefore()
MIDP 2.0                String getSerialNumber()
MIDP 2.0                String getSigAlgName()
MIDP 2.0                String getSubject()
MIDP 2.0                String getType()
MIDP 2.0                String getVersion()

CertificateException

javax.microedition.pki

[View full width]
   Object
        Throwable
            Exception
               java.io.IOException
MIDP 2.0           CertificateException

MIDP 2.0                   byte BAD_EXTENSIONS
MIDP 2.0                   byte BROKEN_CHAIN
MIDP 2.0                   byte CERTIFICATE_CHAIN_TOO_LONG
MIDP 2.0                       CertificateException(Certificate certificate, byte status)
MIDP 2.0                       CertificateException(String message, Certificate certificate, byte status)
MIDP 2.0                   byte EXPIRED
MIDP 2.0           Certificate getCertificate()
MIDP 2.0                  byte getReason()
MIDP 2.0                   byte INAPPROPRIATE_KEY_USAGE
MIDP 2.0                   byte MISSING_SIGNATURE
MIDP 2.0                   byte NOT_YET_VALID
MIDP 2.0                   byte ROOT_CA_EXPIRED
MIDP 2.0                   byte SITENAME_MISMATCH
MIDP 2.0                   byte UNAUTHORIZED_INTERMEDIATE_CA
MIDP 2.0                   byte UNRECOGNIZED_ISSUER
MIDP 2.0                   byte UNSUPPORTED_PUBLIC_KEY_TYPE
MIDP 2.0                   byte UNSUPPORTED_SIGALG
MIDP 2.0                   byte VERIFICATION_FAILED

Choice

javax.microedition.lcdui

Choice

                           int append(String stringPart, Image imagePart)
                          void delete(int elementNum)
MIDP 2.0                  void deleteAll()
                            int EXCLUSIVE
MIDP 2.0                   int getFitPolicy()
MIDP 2.0                  Font getFont(int elementNum)
                         Image getImage(int elementNum)
                           int getSelectedFlags(boolean[] selectedArray_return)
                           int getSelectedIndex()
                        String getString(int elementNum)
                            int IMPLICIT
                          void insert(int elementNum, String stringPart, Image imagePart)
                       boolean isSelected(int elementNum)
                            int MULTIPLE
MIDP 2.0                    int POPUP
                          void set(int elementNum, String stringPart, Image imagePart)
MIDP 2.0                  void setFitPolicy(int fitPolicy)
MIDP 2.0                  void setFont(int elementNum, Font font)
                          void setSelectedFlags(boolean[] selectedArray)
                          void setSelectedIndex(int elementNum, boolean selected)
                           int size()
MIDP 2.0                    int TEXT_WRAP_DEFAULT
MIDP 2.0                    int TEXT_WRAP_OFF
MIDP 2.0                    int TEXT_WRAP_ON

ChoiceGroup

javax.microedition.lcdui

[View full width]
Object
     Item
         ChoiceGroup                            Choice

                           int append(String stringPart, Image imagePart)
                                ChoiceGroup(String label, int choiceType)
                                ChoiceGroup(String label, int choiceType, String stringElements, Image imageElements)
                          void delete(int elementNum)
MIDP 2.0                  void deleteAll()
MIDP 2.0                   int getFitPolicy()
MIDP 2.0                  Font getFont(int elementNum)
                         image getImage(int elementNum)
                           int getSelectedFlags(boolean[] selectedArray_return)
                           int getSelectedIndex()
                        String getString(int elementNum)
                          void insert(int elementNum, String stringPart, Image imagePart)
                       boolean isSelected(int elementNum)
                          void set(int elementNum, String stringPart, Image imagePart)
MIDP 2.0                  void setFitPolicy(int fitPolicy)
MIDP 2.0                  void setFont(int elementNum, Font font)
                          void setSelectedFlags(boolean[] selectedArray)
                          void setSelectedIndex(int elementNum, boolean selected)
                           int size()

Command

javax microedition.lcdui

[View full width]
Object
      Command

                            int BACK
                            int CANCEL
                               Command(String label, int commandType, int priority)
MIDP 2.0                       Command(String shortLabel, String longLabel, int commandType, int priority)
                            int EXIT
                           int getCommandType()
                        String getLabel()
MIDP 2.0                String getLongLabel()
                           int getPriority()
                            int HELP
                            int ITEM
                            int OK
                            int SCREEN
                            int STOP

CommandListener

javax.microedition.lcdui

CommandListener

                          void commandAction(Command c, Displayable d)

CommConnection

javax.microedition.io

MIDP 2.0    CommConnection                     StreamConnection

MIDP 2.0                   int getBaudRate()
MIDP 2.0                   int setBaudRate(int baudrate)

Control

javax.microedition.media

MIDP 2.0    Control

Controllable

javax.microedition.media

MIDP 2.0   Controllable

MIDP 2.0                 Control getControl(String controlType)
MIDP 2.0               Control[] getControls()

CustomItem

javax.microedition.lcdui

[View full width]
    Object
         Item
MIDP 2.0     CustomItem

MIDP 2.0                         CustomItem(String label)
MIDP 2.0                   int getGameAction(int keyCode)
MIDP 2.0                     int getInteractionModes()
MIDP 2.0                     int getMinContentHeight()
MIDP 2.0                     int getMinContentWidth()
MIDP 2.0                     int getPrefContentHeight(int width)
MIDP 2.0                     int getPrefContentWidth(int height)
MIDP 2.0                   void hideNotify()
MIDP 2.0                    void invalidate()
MIDP 2.0                      int KEY_PRESS
MIDP 2.0                      int KEY_RELEASE
MIDP 2.0                      int KEY_REPEAT
MIDP 2.0                   void keyPressed(int keyCode)
MIDP 2.0                   void keyReleased(int keyCode)
MIDP 2.0                   void keyRepeated(int keyCode)
MIDP 2.0                      int NONE
MIDP 2.0                   void paint(Graphics g, int w, int h)
MIDP 2.0                     int POINTER_DRAG
MIDP 2.0                     int POINTER_PRESS
MIDP 2.0                     int POINTER_RELEASE
MIDP 2.0                   void pointerDragged(int x, int y)
MIDP 2.0                   void pointerPressed(int x, int y)
MIDP 2.0                   void pointerReleased(int x, int y)
MIDP 2.0                   void repaint()
MIDP 2.0                   void repaint(int x, int y, int w, int h)
MIDP 2.0                   void showNotify()
MIDP 2.0                   void sizeChanged(int w, int h)
MIDP 2.0                      int TRAVERSE_HORIZONTAL
MIDP 2.0                      int TRAVERSE_VERTICAL
MIDP 2.0                boolean traverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout)
MIDP 2.0                   void traverseOut()

DateField

javax.microedition.lcdui

[View full width]
Object
      Item
           DateField

                            int DATE
                            int DATE_TIME
                               DateField(String label, int mode)
                               DateField(String label, int mode, java.util.TimeZone timeZone)
                java.util.Date getDate()
                           int getInputMode()
                          void setDate(java.util.Date date)
                          void setInputMode(int mode)
                             int TIME

Display

javax.microedition.lcdui

[View full width]
Object
      Display

MIDP 2.0                    int ALERT
                          void callSerially(Runnable r)
MIDP 2.0                    int CHOICE_GROUP_ELEMENT
MIDP 2.0                    int COLOR_BACKGROUND
MIDP 2.0                    int COLOR_BORDER
MIDP 2.0                    int COLOR_FOREGROUND
MIDP 2.0                    int COLOR_HIGHLIGHTED_BACKGROUND
MIDP 2.0                    int COLOR_HIGHLIGHTED_BORDER
MIDP 2.0                    int COLOR_HIGHLIGHTED_FOREGROUND
MIDP 2.0               boolean flashBacklight(int duration)
MIDP 2.0                   int getBestImageHeight(int imageType)
MIDP 2.0                   int getBestImageWidth(int imageType)
MIDP 2.0                   int getBorderStyle(boolean highlighted)
MIDP 2.0                   int getColor(int colorSpecifier)
                   Displayable getCurrent()
                       Display getDisplay(javax.microedition.midlet.MIDlet m)
                       boolean isColor()
MIDP 2.0                    int LIST_ELEMENT
MIDP 2.0                   int numAlphaLevels()
                           int numColors()
                          void setCurrent(Alert alert, Displayable nextDisplayable)
                          void setCurrent(Displayable nextDisplayable)
MIDP 2.0                  void setCurrentItem(Item item)
MIDP 2.0               boolean vibrate(int duration)

Displayable

javax.microedition.lcdui

[View full width]
Object
      Displayable

                          void addCommand(Command cmd)
MIDP 2.0                    int getHeight()
MIDP 2.0                Ticker getTicker()
MIDP 2.0                String getTitle()
MIDP 2.0                   int getWidth()
                       boolean isShown()
                          void removeCommand(Command cmd)
                          void setCommandListener(CommandListener l)
MIDP 2.0                  void setTicker(Ticker ticker)
MIDP 2.0                  void setTitle(String s)
MIDP 2.0                   void sizeChanged(int w, int h)

Font

javax.microedition.lcdui

[View full width]
Object
      Font

                             int charsWidth(char[] ch, int offset, int length)
                             int charWidth(char ch)
                              int FACE_MONOSPACE
                              int FACE_PROPORTIONAL
                              int FACE_SYSTEM
MIDP 2.0                      int FONT_INPUT_TEXT
MIDP 2.0                      int FONT_STATIC_TEXT
                             int getBaselinePosition()
                            Font getDefaultFont()
                             int getFace()
MIDP 2.0                    Font getFont(int fontSpecifier)
                            Font getFont(int face, int style, int size)
                             int getHeight()
                             int getSize()
                             int getStyle()
                        boolean isBold()
                        boolean isItalic()
                        boolean isPlain()
                        boolean isUnderlined()
                             int SIZE_LARGE
                             int SIZE_MEDIUM
                             int SIZE_SMALL
                            int stringWidth(String str)
                             int STYLE_BOLD
                             int STYLE_ITALIC
                             int STYLE_PLAIN
                             int STYLE_UNDERLINED
                            int substringWidth(String str, int offset, int len)

Form

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Screen
             Form

                           int append(Image img)
                           int append(Item item)
                           int append(String str)
                          void delete(int itemNum)
MIDP 2.0                  void deleteAll()
                                Form(String title)
                                Form(String title, Item items)
                          Item get(int itemNum)
MIDP 2.0                   int getHeight()
MIDP 2.0                   int getWidth()
                          void insert(int itemNum, Item item)
                          void set(int itemNum, Item item)
                          void setItemStateListener(ItemStateListener iListener)
                           int size()

GameCanvas

javax.microedition.lcdui.game

[View full width]
   Object
         javax.microedition.lcdui.Displayable
             javax.microedition.lcdui.Canvas
MIDP 2.0         GameCanvas

MIDP 2.0                                       int DOWN_PRESSED
MIDP 2.0                                       int FIRE_PRESSED
MIDP 2.0                                     void flushGraphics()
MIDP 2.0                                     void flushGraphics(int x, int y, int width, int height)
MIDP 2.0                                       int GAME_A_PRESSED
MIDP 2.0                                       int GAME_B_PRESSED
MIDP 2.0                                       int GAME_C_PRESSED
MIDP 2.0                                       int GAME_D_PRESSED
MIDP 2.0                                           GameCanvas(boolean suppressKeyEvents)
MIDP 2.0         javax.microedition.lcdui.Graphics getGraphics()
MIDP 2.0                                      int getKeyStates()
MIDP 2.0                                       int LEFT_PRESSED
MIDP 2.0                                     void paint(javax.microedition.lcdui.Graphics g)
MIDP 2.0                                       int RIGHT_PRESSED
MIDP 2.0                                       int UP_PRESSED

Gauge

javax.microedition.lcdui

[View full width]
Object
      Item
          Gauge

MIDP 2.0                    int CONTINUOUS_IDLE
MIDP 2.0                    int CONTINUOUS_RUNNING
                               Gauge(String label, boolean interactive, int maxValue, int initialValue)
                           int getMaxValue()
                           int getValue()
MIDP 2.0                    int INCREMENTAL_IDLE
MIDP 2.0                    int INCREMENTAL_UPDATING
MIDP 2.0                    int INDEFINITE
                       boolean isInteractive()
                          void setMaxValue(int maxValue)
                          void setValue(int value)

Graphics

javax.microedition.lcdui

[View full width]
Object
      Graphics

                           int BASELINE
                           int BOTTOM
                         void clipRect(int x, int y, int width, int height)
MIDP 2.0                 void copyArea(int x_src, int y_src, int width, int height, int x_dest, int y_dest, int anchor)
                           int DOTTED
                         void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
                         void drawChar(char character, int x, int y, int anchor)
                         void drawChars(char[] data, int offset, int length, int x, int y, int anchor)
                         void drawImage(Image img, int x, int y, int anchor)
                         void drawLine(int x1, int y1, int x2, int y2)
                         void drawRect(int x, int y, int width, int height)
MIDP 2.0                 void drawRegion(Image src, int x_src, int y_src, int width, int height, int transform, int x_dest, int y_dest, int anchor)
MIDP 2.0                 void drawRGB(int[] rgbData, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha)
                         void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
                         void drawString(String str, int x, int y, int anchor)
                         void drawSubstring(String str, int offset, int len, int x, int y, int anchor)
                         void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
                         void fillRect(int x, int y, int width, int height)
                         void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
MIDP 2.0                 void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
                          int getBlueComponent()
                          int getClipHeight()
                          int getClipWidth()
                          int getClipX()
                          int getClipY()
                          int getColor()
MIDP 2.0                  int getDisplayColor(int color)
                         Font getFont()
                          int getGrayScale()
                          int getGreenComponent()
                          int getRedComponent()
                          int getStrokeStyle()
                          int getTranslateX()
                          int getTranslateY()
                           int HCENTER
                           int LEFT
                           int RIGHT
                         void setClip(int x, int y, int width, int height)
                         void setColor(int RGB)
                         void setColor(int red, int green, int blue)
                         void setFont(Font font)
                         void setGrayScale(int value)
                         void setStrokeStyle(int style)
                           int SOLID
                           int TOP
                         void translate(int x, int y)
                           int VCENTER

HttpConnection

javax.microedition.io

HttpConnection                          ContentConnection

                String GET
                 long getDate() throws java.io.IOException
                 long getExpiration() throws java.io.IOException
               String getFile()
               String getHeaderField(int n) throws java.io.IOException
               String getHeaderField(String name) throws java.io.IOException
                 long getHeaderFieldDate(String name, long def) throws java.io.IOException
                  int getHeaderFieldInt(String name, int def) throws java.io.IOException
               String getHeaderFieldKey(int n) throws java.io.IOException
               String getHost()
                 long getLastModified() throws java.io.IOException
                  int getPort()
               String getProtocol()
               String getQuery()
               String getRef()
               String getRequestMethod()
               String getRequestProperty(String key)
                  int getResponseCode() throws java.io.IOException
               String getResponseMessage() throws java.io.IOException
               String getURL()
                String HEAD
                   int HTTP_ACCEPTED
                   int HTTP_BAD_GATEWAY
                   int HTTP_BAD_METHOD
                   int HTTP_BAD_REQUEST
                   int HTTP_CLIENT_TIMEOUT
                   int HTTP_CONFLICT
                   int HTTP_CREATED
                   int HTTP_ENTITY_TOO_LARGE
                   int HTTP_EXPECT_FAILED
                   int HTTP_FORBIDDEN
                   int HTTP_GATEWAY_TIMEOUT
                   int HTTP_GONE
                   int HTTP_INTERNAL_ERROR
                   int HTTP_LENGTH_REQUIRED
                   int HTTP_MOVED_PERM
                   int HTTP_MOVED_TEMP
                   int HTTP_MULT_CHOICE
                   int HTTP_NO_CONTENT
                   int HTTP_NOT_ACCEPTABLE
                   int HTTP_NOT_AUTHORITATIVE
                   int HTTP_NOT_FOUND
                   int HTTP_NOT_IMPLEMENTED
                   int HTTP_NOT_MODIFIED
                   int HTTP_OK
                   int HTTP_PARTIAL
                   int HTTP_PAYMENT_REQUIRED
                   int HTTP_PRECON_FAILED
                   int HTTP_PROXY_AUTH
                   int HTTP_REQ_TOO_LONG
                   int HTTP_RESET
                   int HTTP_SEE_OTHER
                   int HTTP_TEMP_REDIRECT
                   int HTTP_UNAUTHORIZED
                   int HTTP_UNAVAILABLE
                   int HTTP_UNSUPPORTED_RANGE
                   int HTTP_UNSUPPORTED_TYPE
                   int HTTP_USE_PROXY
                   int HTTP_VERSION
                String POST
                 void setRequestMethod(String method) throws java.io.IOException
                 void setRequestProperty(String key, String value) throws java.io.IOException

HttpsConnection

javax.microedition.io

MIDP 2.0    HttpsConnection                  HttpConnection

MIDP 2.0                   int getPort()
MIDP 2.0          SecurityInfo getSecurityInfo() throws java.io.IOException

IllegalStateException

java.lang

[View full width]
Object
      Throwable
         Exception
            RuntimeException
               IllegalStateException

                            IllegalStateException()
                            IllegalStateException(String s)

Image

javax.microedition.lcdui

[View full width]
Object
      Image

                       Image createImage(byte[] imageData, int imageOffset, int imageLength)
                       Image createImage(Image source)
MIDP 2.0               Image createImage(Image image, int x, int y, int width, int height, int transform)
MIDP 2.0               Image createImage(java.io.InputStream stream) throws java.io.IOException
                       Image createImage(int width, int height)
                       Image createImage(String name) throws java.io.IOException
MIDP 2.0               Image createRGBImage(int[] rgb, int width, int height, boolean processAlpha)
                   Graphics getGraphics()
                        int getHeight()
MIDP 2.0               void getRGB(int[] rgbData, int offset, int scanlength, int x, int y, int width, int height)
                        int getWidth()
                    boolean isMutable()

ImageItem

javax.microedition.lcdui

[View full width]
Object
      Item
          ImageItem

                       String getAltText()
MIDP 2.0                  int getAppearanceMode()
                        Image getImage()
                          int getLayout()
                               ImageItem(String label, Image img, int layout, String altText)
MIDP 2.0                       ImageItem(String label, Image image, int layout, String altText, int appearanceMode)
                           int LAYOUT_CENTER
                           int LAYOUT_DEFAULT
                           int LAYOUT_LEFT
                           int LAYOUT_NEWLINE_AFTER
                           int LAYOUT_NEWLINE_BEFORE
                           int LAYOUT_RIGHT
                         void setAltText(String text)
                         void setImage(Image img)
                         void setLayout(int layout)

InvalidRecordIDException

javax.microedition.rms

[View full width]
Object
      Throwable
         Exception
            RecordStoreException
               InvalidRecordIDException

                           InvalidRecordIDException()
                           InvalidRecordIDException(String message)

Item

javax.microedition.lcdui

[View full width]
Object
      Item

MIDP 2.0                  void addCommand(Command cmd)
MIDP 2.0                    int BUTTON
                        String getLabel()
MIDP 2.0                   int getLayout()
MIDP 2.0                   int getMinimumHeight()
MIDP 2.0                   int getMinimumWidth()
MIDP 2.0                   int getPreferredHeight()
MIDP 2.0                   int getPreferredWidth()
MIDP 2.0                    int HYPERLINK
MIDP 2.0                    int LAYOUT_2
MIDP 2.0                    int LAYOUT_BOTTOM
MIDP 2.0                    int LAYOUT_CENTER
MIDP 2.0                    int LAYOUT_DEFAULT
MIDP 2.0                    int LAYOUT_EXPAND
MIDP 2.0                    int LAYOUT_LEFT
MIDP 2.0                    int LAYOUT_NEWLINE_AFTER
MIDP 2.0                    int LAYOUT_NEWLINE_BEFORE
MIDP 2.0                    int LAYOUT_RIGHT
MIDP 2.0                    int LAYOUT_SHRINK
MIDP 2.0                    int LAYOUT_TOP
MIDP 2.0                    int LAYOUT_VCENTER
MIDP 2.0                    int LAYOUT_VEXPAND
MIDP 2.0                    int LAYOUT_VSHRINK
MIDP 2.0                  void notifyStateChanged()
MIDP 2.0                     int PLAIN
MIDP 2.0                  void removeCommand(Command cmd)
MIDP 2.0                  void setDefaultCommand(Command cmd)
MIDP 2.0                  void setItemCommandListener(ItemCommandListener l)
                          void setLabel(String label)
MIDP 2.0                  void setLayout(int layout)
MIDP 2.0                  void setPreferredSize(int width, int height)

ItemCommandListener

javax.microedition.lcdui

MIDP 2.0   ItemCommandListener

                         void commandAction(Command c, Item item)

ItemStateListener

javax.microedition.lcdui

ItemStateListener

                         void ItemStateChanged(Item item)

Layer

javax.microedition.lcdui.game

[View full width]
        Object
MIDP 2.0      Layer

MIDP 2.0                    int getHeight()
MIDP 2.0                    int getWidth()
MIDP 2.0                    int getX()
MIDP 2.0                    int getY()
MIDP 2.0                boolean isVisible()
MIDP 2.0                   void move(int dx, int dy)
MIDP 2.0                    void paint(javax.microedition.lcdui.Graphics g)
MIDP 2.0                   void setPosition(int x, int y)
MIDP 2.0                   void setVisible(boolean visible)

LayerManager

javax.microedition.lcdui.game

[View full width]
        Object
MIDP 2.0      LayerManager

MIDP 2.0                  void append(Layer l)
MIDP 2.0                 Layer getLayerAt(int index)
MIDP 2.0                   int getSize()
MIDP 2.0                  void insert(Layer l, int index)
MIDP 2.0                        LayerManager()
MIDP 2.0                  void paint(javax.microedition.lcdui.Graphics g, int x, int y)
MIDP 2.0                  void remove(Layer l)
MIDP 2.0                  void setViewWindow(int x, int y, int width, int height)

List

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Screen
             List                         Choice

                           int append(String stringPart, Image imagePart)
                          void delete(int elementNum)
                          void deleteAll()
MIDP 2.0                   int getFitPolicy()
MIDP 2.0                  Font getFont(int elementNum)
                         Image getImage(int elementNum)
                           int getSelectedFlags(boolean[] selectedArray_return)
                           int getSelectedIndex()
                        String getString(int elementNum)
                          void insert(int elementNum, String stringPart, Image imagePart)
                       boolean isSelected(int elementNum)
                                List(String title, int listType)
                                List(String title, int listType, String stringElements, Image imageElements)
MIDP 2.0                  void removeCommand(Command cmd)
                        Command SELECT_COMMAND
                          void set(int elementNum, String stringPart, Image imagePart)
MIDP 2.0                  void setFitPolicy(int fitPolicy)
MIDP 2.0                  void setFont(int elementNum, Font font)
MIDP 2.0                  void setSelectCommand(Command command)
                          void setSelectedFlags(boolean[] selectedArray)
                          void setSelectedIndex(int elementNum, boolean selected)
                           int size()

Manager

javax.microedition.media

[View full width]
        Object
MIDP 2.0      Manager

MIDP 2.0                 Player createPlayer(java.io.InputStream stream, String type) throws java.io.IOException, MediaException
MIDP 2.0                 Player createPlayer(String locator) throws java.io.IOException, MediaException
MIDP 2.0               String[] getSupportedContentTypes(String protocol)
MIDP 2.0               String[] getSupportedProtocols(String content_type)
MIDP 2.0                  void playTone(int note, int duration, int volume) throws MediaException
MIDP 2.0                 String TONE_DEVICE_LOCATOR

MediaException

javax.microedition.media

[View full width]
    Object
          Throwable
             Exception
MIDP 2.0       MediaException

MIDP 2.0                        MediaException()
MIDP 2.0                        MediaException(String reason)

MIDlet

javax.microedition.midlet

[View full width]
Object
      MIDlet

MIDP 2.0                    int checkPermission(String permission)
                            void destroyApp(boolean unconditional) throws MIDletStateChangeException
                         String getAppProperty(String key)
                                 MIDlet()
                           void notifyDestroyed()
                           void notifyPaused()
                            void pauseApp()
MIDP 2.0                boolean platformRequest(String URL) throws javax.microedition.io.ConnectionNotFoundException
                           void resumeRequest()
                            void startApp() throws MIDletStateChangeException

MIDletStateChangeException

javax.microedition.midlet

[View full width]
Object
      Throwable
         Exception
            MIDletStateChangeException

                                MIDletStateChangeException()
                                MIDletStateChangeException(String s)

Player

javax.microedition.media

MIDP 2.0   Player                              Controllable

MIDP 2.0                  void addPlayerListener(PlayerListener playerListener)
MIDP 2.0                  void close()
MIDP 2.0                    int CLOSED
MIDP 2.0                  void deallocate()
MIDP 2.0                String getContentType()
MIDP 2.0                  long getDuration()
MIDP 2.0                  long getMediaTime()
MIDP 2.0                   int getState()
MIDP 2.0                  void prefetch() throws MediaException
MIDP 2.0                    int PREFETCHED
MIDP 2.0                  void realize() throws MediaException
MIDP 2.0                    int REALIZED
MIDP 2.0                  void removePlayerListener(PlayerListener playerListener)
MIDP 2.0                  void setLoopCount(int count)
MIDP 2.0                  long setMediaTime(long now) throws MediaException
MIDP 2.0                  void start() throws MediaException
MIDP 2.0                    int STARTED
MIDP 2.0                  void stop() throws MediaException
MIDP 2.0                   long TIME_UNKNOWN
MIDP 2.0                    int UNREALIZED

PlayerListener

javax.microedition.media

MIDP 2.0   PlayerListener

MIDP 2.0                  String CLOSED
MIDP 2.0                  String DEVICE_AVAILABLE
MIDP 2.0                  String DEVICE_UNAVAILABLE
MIDP 2.0                  String DURATION_UPDATED
MIDP 2.0                  String END_OF_MEDIA
MIDP 2.0                  String ERROR
MIDP 2.0                   void playerUpdate(Player player, String event, Object eventData)
MIDP 2.0                  String STARTED
MIDP 2.0                  String STOPPED
MIDP 2.0                  String VOLUME_CHANGED

PushRegistry

javax.microedition.io

[View full width]
       Object
MIDP 2.0     PushRegistry

MIDP 2.0                 String getFilter(String connection)
MIDP 2.0                 String getMIDlet(String connection)
MIDP 2.0               String[] listConnections(boolean available)
MIDP 2.0                   long registerAlarm(String midlet, long time) throws ClassNotFoundException, ConnectionNotFoundException
MIDP 2.0                   void registerConnection(String connection, String midlet, String filter) throws ClassNotFoundException, java.io.IOException
MIDP 2.0                boolean unregisterConnection(String connection)

RecordComparator

javax.microedition.rms

RecordComparator

                            int compare(byte[] rec1, byte[] rec2)
                             int EQUIVALENT
                             int FOLLOWS
                             int PRECEDES

RecordEnumeration

javax.microedition.rms

RecordEnumeration

                          void destroy()
                       boolean hasNextElement()
                       boolean hasPreviousElement()
                       boolean isKeptUpdated()
                          void keepUpdated(boolean keepUpdated)
                        byte[] nextRecord() throws InvalidRecordIDException, RecordStoreNotOpenException, RecordStoreException
                           int nextRecordId() throws InvalidRecordIDException
                           int numRecords()
                        byte[] previousRecord() throws InvalidRecordIDException, RecordStoreNotOpenException, RecordStoreException
                           int previousRecordId() throws InvalidRecordIDException
                          void rebuild()
                          void reset()

RecordFilter

javax.microedition.rms

RecordFilter

                       boolean matches(byte[] candidate)

RecordListener

javax.microedition.rms

RecordListener

                          void recordAdded(RecordStore recordStore, int recordId)
                          void recordChanged(RecordStore recordStore, int recordId)
                          void recordDeleted(RecordStore recordStore, int recordId)

RecordStore

javax.microedition.rms

[View full width]
Object
      RecordStore

                           int addRecord(byte[] data, int offset, int numBytes) throws RecordStoreNotOpenException, RecordStoreException, RecordStoreFullException
                          void addRecordListener(RecordListener listener)
MIDP 2.0                    int AUTHMODE_ANY
MIDP 2.0                    int AUTHMODE_PRIVATE
                          void closeRecordStore() throws RecordStoreNotOpenException, RecordStoreException
                          void deleteRecord(int recordId) throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
                           void deleteRecordStore(String recordStoreName) throws RecordStoreException, RecordStoreNotFoundException
             RecordEnumeration enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated) throws RecordStoreNotOpenException
                          long getLastModified() throws RecordStoreNotOpenException
                        String getName() throws RecordStoreNotOpenException
                           int getNextRecordID() throws RecordStoreNotOpenException, RecordStoreException
                           int getNumRecords() throws RecordStoreNotOpenException
                        byte[] getRecord(int recordId) throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
                           int getRecord(int recordId, byte[] buffer, int offset) throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
                           int getRecordSize(int recordId) throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
                           int getSize() throws RecordStoreNotOpenException
                           int getSizeAvailable() throws RecordStoreNotOpenException
                           int getVersion() throws RecordStoreNotOpenException
                       String[] listRecordStores()
                    RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary) throws RecordStoreException, RecordStoreFullException, RecordStoreNotFoundException
MIDP 2.0            RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary, int authmode, boolean writable) throws RecordStoreException, RecordStoreFullException, RecordStoreNotFoundException
MIDP 2.0            RecordStore openRecordStore(String recordStoreName, String vendorName, String suiteName) throws RecordStoreException, RecordStoreNotFoundException
                           void removeRecordListener(RecordListener listener)
MIDP 2.0                   void setMode(int authmode, boolean writable) throws RecordStoreException
                           void setRecord(int recordId, byte[] newData, int offset, int numBytes) throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException, RecordStoreFullException

RecordStoreException

javax.microedition.rms

[View full width]
Object
      Throwable
         Exception
            RecordStoreException

                          RecordStoreException()
                          RecordStoreException(String message)

RecordStoreFullException

javax.microedition.rms

[View full width]
Object
      Throwable
         Exception
             RecordStoreException
                RecordStoreFullException

                           RecordStoreFullException()
                           RecordStoreFullException(String message)

RecordStoreNotFoundException

javax.microedition.rms

[View full width]
Object
      Throwable
         Exception
            RecordStoreException
               RecordStoreNotFoundException

                                RecordStoreNotFoundException()
                                RecordStoreNotFoundException(String message)

RecordStoreNotOpenException

javax.microedition.rms

[View full width]
Object
      Throwable
         Exception
            RecordStoreException
               RecordStoreNotOpenException

                         RecordStoreNotOpenException()
                         RecordStoreNotOpenException(String message)

Screen

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Screen

SecureConnection

javax.microedition.io

MIDP 2.0   SecureConnection                SocketConnection

MIDP 2.0          SecurityInfo getSecurityInfo() throws java.io.IOException

SecurityInfo

javax.microedition.io

MIDP 2.0   SecurityInfo

MIDP 2.0                                  String getCipherSuite()
MIDP 2.0                                  String getProtocolName()
MIDP 2.0                                  String getProtocolVersion()
MIDP 2.0      javax.microedition.pki.Certificate getServerCertificate()

ServerSocketConnection

javax.microedition.io

MIDP 2.0   ServerSocketConnection        StreamConnectionNotifier

MIDP 2.0                String getLocalAddress() throws java.io.IOException
MIDP 2.0                   int getLocalPort() throws java.io.IOException

SocketConnection

javax.microedition.io

MIDP 2.0   SocketConnection              StreamConnection

MIDP 2.0                    byte DELAY
MIDP 2.0                 String getAddress() throws java.io.IOException
MIDP 2.0                 String getLocalAddress() throws java.io.IOException
MIDP 2.0                    int getLocalPort() throws java.io.IOException
MIDP 2.0                    int getPort() throws java.io.IOException
MIDP 2.0                    int getSocketOption(byte option) throws IllegalArgumentException, java.io.IOException
MIDP 2.0                    byte KEEPALIVE
MIDP 2.0                    byte LINGER
MIDP 2.0                    byte RCVBUF
MIDP 2.0                   void setSocketOption(byte option, int value) throws IllegalArgumentException, java.io.IOException
MIDP 2.0                    byte SNDBUF

Spacer

javax.microedition.lcdui

[View full width]
   Object
         Item
MIDP 2.0     Spacer

MIDP 2.0                  void addCommand(Command cmd)
MIDP 2.0                  void setDefaultCommand(Command cmd)
MIDP 2.0                  void setLabel(String label)
MIDP 2.0                  void setMinimumSize(int minWidth, int minHeight)
MIDP 2.0                        Spacer(int minWidth, int minHeight)

Sprite

javax.microedition.lcdui.game

[View full width]
   Object
         Layer
MIDP 2.0     Sprite

MIDP 2.0                boolean collidesWith(javax.microedition.lcdui.Image image, int x, int y, boolean pixelLevel)
MIDP 2.0                boolean collidesWith(Sprite s, boolean pixelLevel)
MIDP 2.0                boolean collidesWith(TiledLayer t, boolean pixelLevel)
MIDP 2.0                   void defineCollisionRectangle(int x, int y, int width, int height)
MIDP 2.0                   void defineReferencePixel(int x, int y)
MIDP 2.0                    int getFrame()
MIDP 2.0                    int getFrameSequenceLength()
MIDP 2.0                    int getRawFrameCount()
MIDP 2.0                    int getRefPixelX()
MIDP 2.0                    int getRefPixelY()
MIDP 2.0                   void nextFrame()
MIDP 2.0                   void paint(javax.microedition.lcdui.Graphics g)
MIDP 2.0                  void prevFrame()
MIDP 2.0                  void setFrame(int sequenceIndex)
MIDP 2.0                  void setFrameSequence(int[] sequence)
MIDP 2.0                  void setImage(javax.microedition.lcdui.Image img, int frameWidth, int frameHeight)
MIDP 2.0                  void setRefPixelPosition(int x, int y)
MIDP 2.0                  void setTransform(int transform)
MIDP 2.0                        Sprite(javax.microedition.lcdui.Image image)
MIDP 2.0                        Sprite(javax.microedition.lcdui.Image image, int frameWidth, int frameHeight)
MIDP 2.0                        Sprite(Sprite s)
MIDP 2.0                    int TRANS_MIRROR
MIDP 2.0                    int TRANS_MIRROR_ROT180
MIDP 2.0                    int TRANS_MIRROR_ROT270
MIDP 2.0                    int TRANS_MIRROR_ROT90
MIDP 2.0                    int TRANS_NONE
MIDP 2.0                    int TRANS_ROT180
MIDP 2.0                    int TRANS_ROT270
MIDP 2.0                    int TRANS_ROT90

StringItem

javax.microedition.lcdui

[View full width]
Object
      Item
          StringItem

MIDP 2.0                   int getAppearanceMode()
MIDP 2.0                  Font getFont()
                        String getText()
MIDP 2.0                  void setFont(Font font)
                          void setText(String text)
                                StringItem(String label, String text)
MIDP 2.0                        StringItem(String label, String text, int appearanceMode)

TextBox

javax.microedition.lcdui

[View full width]
Object
      Displayable
          Screen
             TextBox

                          void delete(int offset, int length)
                           int getCaretPosition()
                           int getChars(char[] data)
                           int getConstraints()
                           int getMaxSize()
                        String getString()
                          void insert(char[] data, int offset, int length, int position)
                          void insert(String src, int position)
                          void setChars(char[] data, int offset, int length)
                          void setConstraints(int constraints)
MIDP 2.0                  void setInitialInputMode(String characterSubset)
                           int setMaxSize(int maxSize)
                          void setString(String text)
                           int size()
                                TextBox(String title, String text, int maxSize, int constraints)

TextField

javax.microedition.lcdui

[View full width]
Object
      Item
          TextField

                            int ANY
                            int CONSTRAINT_MASK
MIDP 2.0                    int DECIMAL
                          void delete(int offset, int length)
                            int EMAILADDR
                           int getCaretPosition()
                           int getChars(char[] data)
                           int getConstraints()
                           int getMaxSize()
                        String getString()
MIDP 2.0                    int INITIAL_CAPS_SENTENCE
MIDP 2.0                    int INITIAL_CAPS_WORD
                          void insert(char[] data, int offset, int length, int position)
                          void insert(String src, int position)
MIDP 2.0                    int NON_PREDICTIVE
                            int NUMERIC
                            int PASSWORD
                            int PHONENUMBER
MIDP 2.0                    int SENSITIVE
                          void setChars(char[] data, int offset, int length)
                          void setConstraints(int constraints)
MIDP 2.0                  void setInitialInputMode(String characterSubset)
                           int setMaxSize(int maxSize)
                          void setString(String text)
                           int size()
                                TextField(String label, String text, int maxSize, int constraints)
MIDP 2.0                    int UNEDITABLE
                            int URL

Ticker

javax.microedition.lcdui

[View full width]
Object
      Ticker

                        String getString()
                          void setString(String str)
                                Ticker(String str)

TiledLayer

javax.microedition.lcdui.game

[View full width]
    Object
          Layer
MIDP 2.0      TiledLayer

MIDP 2.0                   int createAnimatedTile(int staticTileIndex)
MIDP 2.0                  void fillCells(int col, int row, int numCols, int numRows, int tileIndex)
MIDP 2.0                    int getAnimatedTile(int animatedTileIndex)
MIDP 2.0                    int getCell(int col, int row)
MIDP 2.0                    int getCellHeight()
MIDP 2.0                    int getCellWidth()
MIDP 2.0                    int getColumns()
MIDP 2.0                    int getRows()
MIDP 2.0                   void paint(javax.microedition.lcdui.Graphics g)
MIDP 2.0                   void setAnimatedTile(int animatedTileIndex, int staticTileIndex)
MIDP 2.0                   void setCell(int col, int row, int tileIndex)
MIDP 2.0                   void setStaticTileSet(javax.microedition.lcdui.Image image, int tileWidth, int tileHeight)
MIDP 2.0                        TiledLayer(int columns, int rows, javax.microedition.lcdui.Image image, int tileWidth, int tileHeight)

Timer

java.util

[View full width]
Object
      Timer

                          void cancel()
                          void schedule(TimerTask task, Date time)
                          void schedule(TimerTask task, Date firstTime, long period)
                          void schedule(TimerTask task, long delay)
                          void schedule(TimerTask task, long delay, long period)
                          void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
                          void scheduleAtFixedRate(TimerTask task, long delay, long period)
                                Timer()

TimerTask

java.util

[View full width]
Object
      TimerTask                              Runnable

                       boolean cancel()
                          void run()
                          long scheduledExecutionTime()
                                 TimerTask()

ToneControl

javax.microedition.media.control

MIDP 2.0    ToneControl        javax.microedition.media.Control

MIDP 2.0                    byte BLOCK_END
MIDP 2.0                    byte BLOCK_START
MIDP 2.0                    byte C4
MIDP 2.0                    byte PLAY_BLOCK
MIDP 2.0                    byte REPEAT
MIDP 2.0                    byte RESOLUTION
MIDP 2.0                    byte SET_VOLUME
MIDP 2.0                   void setSequence(byte[] sequence)
MIDP 2.0                    byte SILENCE
MIDP 2.0                    byte TEMPO
MIDP 2.0                    byte VERSION

UDPDatagramConnection

javax.microedition.io

MIDP 2.0    UDPDatagramConnection             DatagramConnection

MIDP 2.0                String getLocalAddress() throws java.io.IOException
MIDP 2.0                   int getLocalPort() throws java.io.IOException

VolumeControl

javax.microedition.media.control

MIDP 2.0    VolumeControl      javax.microedition.media.Control

MIDP 2.0                   int getLevel()
MIDP 2.0               boolean isMuted()
MIDP 2.0                   int setLevel(int level)
MIDP 2.0                  void setMute(boolean mute)


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

Abstract Windowing Toolkit
addCommand
addTicker
Alert 2nd
Screen:Alert
Ticker on Alert
AlertType
alpha-channel
AMS
animated Gauge
ANY
API documentation
MIDP
application
development environment
management
management software
application launch
event-driven
usage scenarios
application management software
application management software (AMS)
application manager
Application provided operations
application push
sample application
application startup
application:descriptor
MIDP:application:descriptor
application:Java
Java application
Arabic
Arabic-Indic digit input
automatic casing
automatic launching
MIDlet
AWT

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

BACK 2nd 3rd
background
background color
backlight
backward navigation
battery life
business applications
button 2nd
BUTTON
byte arrays
converting record data to and from

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

CANCEL 2nd
Canvas 2nd [See also canvas]3rd [See also canvas]4th [See also canvas]
adaptation to device user interface style
class:Canvas: [See also Canvas]2nd [See also Canvas]3rd [See also Canvas]
canvas
events
action
key
pointer
canvas:coordinate system
coordinate system
canvas:redrawing mechanism
redrawing
repainting 2nd 3rd 4th 5th 6th 7th 8th 9th
canvas:visibility
visibility
CDC
Connected Device Configuration: [See CDC]
certificate
root CA
certificate expiration and revocation
Certificate processing for Over-The-Air (OTA) delivery
Choice
ChoiceGroup 2nd
Item:types:ChoiceGroup
class
file
format
loaders
user-defined
Screen
SeeScreen
types
collection
data 2nd
input/output
class:Calendar
class:Time
Calendar;Time
class:CLDC-specific
CLDC:classes:-specific
class:CLDC:derived from J2SE
CLDC:classes:derived from J2SE
class:Date
Date
class:file:format:supported
format:class file:supported
class:file:lookup order
file:class:lookup order
class:file:lookup order:restrictions
file:class:lookup order:restrictions
class:loading
loading:classes
class:system
system:classes
class:types:exception
class:types:error
error classes;exception classes
class:types:utility
utility classes
CLDC
architecture
chapter
configuration:CLDC
Java 2 Micro Edition:configuration:CLDC
Connected, Limited Device Configuration: [See CLDC]
expert group 2nd
goals 2nd
specification
virtual machine differences
user-defined class loaders
CLDC:API documentation
API documentation:CLDC
CLDC:application model
application:model:CLDC
CLDC:libraries:chapter
libraries:CLDC: [See CLDC, libraries]
CLDC:requirements:hardware
requirements:CLDC:hardware
CLDC:requirements:software
requirements:CLDC:software
CLDC:system properties
system:properties
clipping
graphics:clipping 2nd
collection
classes
color
color capabilities 2nd 3rd
color model
graphics:color model
color scheme of a device
COLOR_BORDER
COLOR_FOREGROUND
Command 2nd
command
abstract
listeners
Command
long label
short label
Command label
Command priorities
Command priority
Command type
Command types 2nd
commandAction
system screens
CommandListener 2nd 3rd 4th
Commands
communication ports
Generic Connection framework example
compatibility
concurrency
configuration
Java 2 Micro Edition:configuration 2nd
configuration:requirements
Java 2 Micro Edition:configuration:requirements
connection
establishing
Connection
security properties of
connection
states
closed
connected
setup 2nd
Connection interface
connection:HTTP:using
HTTP:using a connection
container
content area
content size
context-sensitive menu
CONTINUOUS_RUNNING
Control
interface
Current Alignment
current Displayable 2nd 3rd 4th
current screen
custom components
CustomItem 2nd 3rd 4th
adaptation to device user interface style

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

data type classes
datagrams
Generic Connection framework example
DataSource
class
and protocol handling
DateField 2nd
Item:types:DateField
DECIMAL
default Command 2nd
device fonts
device properties
device vibrator
device-provided operations
devices
consumer
specialized nature of
target
characteristics
Display 2nd 3rd
Displayable 2nd 3rd 4th 5th
actually visible
automatically changing
drawing
images
mutable
drawing:arcs
arcs:drawing and filling
filling:arcs
drawing:lines
lines:drawing
drawing:rectangles
filling:rectangles
rectangles:drawing and filling
drawing:rectangles:rounded
filling:rectangles:rounded
rectangles:rounded:drawing and filling 2nd
drawing:text
text:drawing 2nd 3rd 4th

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

editing modes
EMAILADDR
embedded systems
encoding:character
character encoding
error handling:CLDC
CLDC:error handling
errors
CLDC:virtual machine differences:errors
events
action
key
pointer
example
NetClientMIDlet
example:timers
timers:example
EXCLUSIVE
EXIT 2nd

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

failure:non-transient
non-transient failure
failure:transient
transient failure
file:application resource
application:resource files
MIDP:application:resources files
file:application-specific resource
application: resource files, specific
finalization
CLDC:finalization
CLDC:virtual machine differences:finalization
flashBacklight
Focus
focus
focus traversal
font
Font 2nd
FONT_INPUT_TEXT
FONT_STATIC_TEXT
fonts
graphics:fonts
foreground 2nd
foreground color
Form 2nd 3rd
Screen>Default Para Font>:Form
Form layout
format
class file

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

Game API
Gauge 2nd
Item:types:Gauge
Generic Connection framework 2nd
basic interface types
example
communication ports
datagrams
general form
HTTP
sockets 2nd
used by MIDP
GET method
request:method:GET
getBestImageHeight
getBestImageWidth
getCipherSuite method
getColor
getCurrent
getDisplay
getFont
getHeight 2nd
getServerCertificate method
getWidth 2nd
Graphics
class:Graphics: [See also graphics]2nd [See also graphics]3rd [See also graphics]
graphics:drawing model
drawing
gray levels

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

HEAD method
request:method:HEAD
headers [See also request headers]
HELP 2nd
hideNotify 2nd
Hiragana script
host operating system 2nd
kernel: [See host operating system]
HTTP
Generic Connection framework example
HTTPS
certificate processing for
HttpsConnection
interface
HttpsConnection interface
hyperlink
HYPERLINK

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

ImageItem 2nd
class:ImageItem
images
creating and using
mutable 2nd
incoming phone call
INCREMENTAL_UPDATING
indefinite Gauge
informational notes
Initial input mode
initial value of current alignment
INITIAL_CAPS_SENTENCE
INITIAL_CAPS_WORD
input constraint
input events
input mechanisms 2nd
input methods 2nd
input mode
Input Modes
input/output classes
InputConnection interface
insertion point
intent of a Command
interaction modes
MIDlet suite
trusted security mode
interface
Connection
Controllable
InputConnection
interface:ContentConnection
ContentConnection interface
interface:DatagramConnection
DatagramConnection interface
interface:HttpConnection
HttpConnection interface
interface:OutputConnection
OutputConnection interface
interface:RecordListener
RecordListener interface
interface:StreamConnection
StreamConnection interface
interface:StreamConnectionNotifier
StreamConnectionNotifier interface
internationalization
CLDC:internationalization
Internet X.509 Public Key Infrastructure
specification
interoperability
isColor
isShown 2nd
Item 2nd
ITEM 2nd 3rd
Item Commands
Item layout
ItemCommandListener
ItemStateListener
ITU-T keypad

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

J2ME [See Java 2 Micro Edition]
Japanese language
Java 2 Micro Edition
architecture
chapter
Java 2 Micro Edition:configuration
configuration
Java 2 Micro Edition:optional package
optional package
Java 2 Micro Edition:profile
profile
Java Application Manager
JAM: [See Java Application Manager]
Java Archive files
JAR: [See Java Archive files]
Java Community Process
JCP: [See Java Community Process]
Java Language Specification:compatibility with
compatibility:with Java Language Specification
Java libraries
Java virtual machine
Java Virtual Machine Specification:compatibility with
compatibility:with Java Virtual Machine Specification

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

K Virtual Machine
KVM: [See K Virtual Machine]
key events
keys

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

label
Latin characters
layout 2nd
layout directives
LAYOUT_2
lcdui events
left-to-right layout
lifecycle of the application
lines:styles
graphics:line styles
List
class:List:SeeList
exclusive choice
implicit
List and Ticker
mutliple choice
setSelectCommand
lists [See List]
localization
locked Item
look and feel

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

Manager
Class
class
media flow controls
Media Framework
Managing
menu 2nd 3rd
MIDI format 2nd
MIDI format (SP-MIDI)
MIDlet
attributes
exiting
states 2nd
active
destroyed
paused
transitions
transitions:how to request
suites
definition
execution environment
packaging
MIDlet Launch
alarm-based
network-based
MIDlet suite
removal
signing
signing certificate
trusted security mode
interaction modes
permissions
protection domain 2nd
MIDlet Suite
updates
MIDlet suite security
caching of results
MIDlet suites
security for
untrusted
MIDlet:application lifecycle
application:MIDlet lifecycle
MIDP
API documentation
chapter
expert group 2nd
goals
libraries
high-level user interface 2nd 3rd
other APIs
chapter
system software
MIDP 2.0 Sound API
video and camera functionality with
MIDP Media Support
MIDP Sound API
Design Goals
introduction
subset of MMAPI
MIDP X.509 Certificate Profile
MIDP, new for 2.0
MIDP application model
MIDP:application:model
application:model:MIDP
MIDP:libraries:networking
serial communications
networking:MIDP libraries;libraries:MIDP
MIDP:libraries:persistence
persistence:MIDP libraries
MIDP:requirements:hardware
requirements:MIDP:hardware
MIDP:requirements:software
requirements:MIDP:software
MIDP:system properties
system:properties
MIDP:timer support
timers
MIDP:timer support: [See also timers]
MIDP:user interface:
user interface:structure [See user interface]
MIDPEG [See MIDP expert group]2nd [See MIDP expert group]3rd [See MIDP expert group]
MIME types
MMAPI
forward compatibility with
Mobile Media API
Mobile Media API, introduction
modal Alert
modifiers
monochrome display
mouse input

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

native applications
native settings
native user interface style
native user interfaces
Navigation
navigation
NetClientMIDlet
HTTP:example
Networking
Secure
New for MIDP 2.0
OTA provisioning
newline characters
NON_PREDICTIVE
numAlphaLevels
number of colors
numColors
NUMERIC
numeric keypad

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

Objects
Media Control
OK 2nd
optimization:implementation
implementation:optimization
optimzation
implementation-level
over-the-air provisioning
user-initiated

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

parsing URLs
URLs:parsing
PASSWORD
PCM wav format
pen input
permissions
MIDlet suite
trusted security mode
phone book application
PHONENUMBER
PLAIN
Player
Class
player
creating
from HTTP locator media
from JAR media
Player
interface
life cycle
Player Creation and Management
Player object
states
PlayerListener
Class
Players
Creating
pointing device
POPUP
portability 2nd
POST method
request:method:POST
pre-verification:off-device
off-device pre-verification
predictive input 2nd
predictive input systems
preferred sizes of images
prelinking
class:prelinking
preloading
class:preloading
preverifier 2nd
profile
Java 2 Micro Edition:profile 2nd
profile:definition
Java 2 Micro Edition:profile:definition
profile:MIDP
Java 2 Micro Edition:profile:MIDP
progress animation
progress bar
progress indicator
property queries
property:CLDC support
CLDC:property support
protection domain
MIDlet suite
trusted security mode
protocol handling
sound and multimedia processing
protocols\
secure
push functionality
push mechanism
push notification
dynamic registration
registration for
static registration
push registry
permissions
security of

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

readers
writers
record
comparing
converting data
enumerating
filtering
listening
manipulating
stores
manipulating
names
Record Management System
RecordComparator interface
interface:RecordComparator
RecordEnumerator interface
interface:RecordEnumerator
RecordFilter interface
interface:RecordFilter
reminders
removeCommand
request
headers
Accept-Language
User-Agent
request:headers
HTTP:request headers
requirements
J2ME
response headers
headers:response
HTTP:response headers
RFC 2437
RFC 2459 2nd
right-to-left layout
RMS [See Record Management System]
RMSMIDlet.java example
example:RMS
ROMizing
class:ROMizing
RSA Encryption Version 2.0
specification

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

sandbox security model (MIDP 1.0)
scope:CLDC
CLDC:scope
scope:MIDP
MIDP:scope
Screen 2nd
SCREEN 2nd
Screen
List [See List]
Screen backlight
screen size
screen:user interface model
user interface:screen model
scrolling 2nd 3rd
Secure Networking
secure protocols
SecureConnection
example code
interface
security of
SecureConnection interface
security for MIDlet suites
security policy for GSM/UMTS devices
SecurityInfo object
select operation
SELECT_COMMAND
SENSITIVE
setCommandListener 2nd
setCurrent
setCurrent(null)
setCurrentItem
setInitialInputMode
setLayout
setTicker
setTitle
showNotify 2nd
signing certificate
MIDlet suite
size of the display
sizeChanged
sockets
example
Generic Connection framework
softkey 2nd
sound and media support
Controls
Manager
Player
SP-MIDI
Spacer 2nd 3rd
Spotless project
SSL
stack maps
standardization
CLDC
J2ME 2nd
MIDP
STOP 2nd
StringItem 2nd
class:StringItem
synchronization
UI
System Screens
system software
MIDP
system sounds

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

table
text editor
text input mode
TEXT_WRAP_OFF
TEXT_WRAP_ON
TextBox
Screen:TextBox
TextField 2nd
Item:types:TextField
textual input
thread groups
daemon groups
CLDC:virtual machine differences:thread groups;CLDC:virtual machine differences:daemon groups
thread-safety
Ticker 2nd
timed Alert
timer
timers
one-shot
repeating
TimerTasks
in UI
TLS
tone generation
ToneControl
interface
touch screen
traversal 2nd
Traversal
trust for MIDlet suites
establishing
using X.509 PKI

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

UNEDITABLE
Unicode
Unicode character blocks
unlocked Item
URL
user interaction models 2nd
one-handed
touch screen
two-handed
user interface
high-level
low-level
user interface:touch input
touch input

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

verification:class file
class:file:verification
verification:runtime
runtime:verification
verifier:runtime
runtime:verifier
vibrate
vibrator
virtual keyboards
VolumeControl
interface

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

WAP (Wireless Application Protocol)
WAP Certificate Profile
specification
WAPCert
specification
window management

[ Team LiB ]


[ Team LiB ]

[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [R] [S] [T] [U] [V] [W] [X]

X.509 certificate
X.509 Certificate Profile for Trusted MIDlet Suites
X.509 PKI
using
to establish trust for MIDlet suite

[ Team LiB ]


Team LiB

Brought to You by

Like the book? Buy it!