The
Wireless Toolkit
Peter
Komisar © Conestoga College version 1.1
/ 2008
reference: User’s Guide Sun JavaTM
Wireless Toolkit for CLDC
Version 2.5.2, Sun Microsystems
Fortunately for us there are simpler ways of developing
MIDlets. It is good to know about the steps involved in
generating a MIDlet application.
Before considering, more elaborate IDE's like NetBeans
we look at what the WTK has to offer. If we are use to it
we can easily transition to a more elaborate IDE if we
find it necessary.
In the last note, we described downloading the Wireless
TookKit, installing it and adding it's path. We now look
at how it can be used to facilitate MIDlet development.
Starting
the Toolkit
On Windows you start the WDK from 'All Programs'.
On Linux, change directories to toolkit/bin. and enter
./ktoolbar.
We saw last class that we could look at existing programs
by opening 'Open Projects'.
The Toolkit has three primary parts.
Toolkit Components
- The user interface
- automates development tasks
- The emulator
- simulates a mobile phone for testing
- utilities
- other uses
- including a text messaging console
- cryptographic utilities
To the mix you need to supply your own text editor.
Toolkit
Features
The Sun JavaTM Wireless Toolkit supports:
- Building and
packaging
- compiling
- preverification
- jar and jad packaging
- Running and
monitoring
- run a MIDlet suite in the emulator or
- use a process resembling installation on a real device
- provided for analysis are a :
- a memory monitor
- a network monitor
- method profiler
- MIDlet suite
signing tools are provided
- for cryptographically signing MIDlet suites
- useful for testing in different protection domains.
An Update Feature Checks every seven days if you need
an update based on system information it collects. Disable
with the following clicks.
Controlling
the Update Feature
Edit > Preferences > click Network Configuration >
check / uncheck 'Check for updates' box.
Toolkit
API Support
Following is a quick summary of APIs supported by the
toolkit with associated links. The list is impressive including
Security, Scalable 2D Vector Graphics, 3D Graphics APIs
and Bluetooth support.
Toolkit Supported APIs
- Mobile Service Architecture
- http://jcp.org/en/jsr/detail?id=248
- Java Technology for the Wireless Industry
- http://jcp.org/en/jsr/detail?id=185
- Connected Limited Device Configuration
- http://jcp.org/en/jsr/detail?id=139
- Mobile Information Device Profile
- http://jcp.org/en/jsr/detail?id=118
- PIM and File PDA Optional Packages for the J2ME Platform
- http://jcp.org/en/jsr/detail?id=75
- Bluetooth and OBEX Java APIs for Bluetooth
- http://jcp.org/en/jsr/detail?id=82
- Mobile Media API
- http://jcp.org/en/jsr/detail?id=135
- J2ME Web Services Specification
- http://jcp.org/en/jsr/detail?id=172
- SATSASecurity and Trust Services API for Java ME
- http://jcp.org/en/jsr/detail?id=177
- Location API for Java ME
- http://jcp.org/en/jsr/detail?id=179
- SIP API for Java ME
- http://jcp.org/en/jsr/detail?id=180
- 3D GraphicsMobile 3D Graphics API for J2ME
- http://jcp.org/en/jsr/detail?id=184
- Wireless Messaging API
- http://jcp.org/en/jsr/detail?id=205
- CHAPI Content Handler API
- http://jcp.org/en/jsr/detail?id=211
- Scalable 2D Vector Graphics API for J2ME
- http://jcp.org/en/jsr/detail?id=226
- Payment API
- http://jcp.org/en/jsr/detail?id=229
- AMMS Advanced Multimedia Supplements
- http://jcp.org/en/jsr/detail?id=234
- MIA Mobile Internationalization API
- http://jcp.org/en/jsr/detail?id=238
- Java Binding for OpenGL® ES API
- http://jcp.org/en/jsr/detail?id=239
- Mobile Service Architecture
- http://jcp.org/en/jsr/detail?id=248
Projects
With Sun's Toolkit "MIDlet suites are organized into
projects, where the end result of one project is one
MIDlet suite. A project contains all of the files that will
be used to build a MIDlet suite, including Java source
files, resource files, and the MIDlet descriptor."
//
a project holds the MIDlet suite and all the pieces
// that were used to create it.
Creating
a Project
- Open the Toolkit as described earlier.
- Click 'New Project'
- Fill in Project and MIDlet Names
- Accept the Default Settings
Notice the important information on the toolkit console
regarding where to put development files is listed on
the Toolkit's UI.
Simple
Cycle
The User Guide Describes the Simple Development
Cycle.
From the most general viewpoint the cycle is as follows.
Edit source code > Build
> Run
- Edit source
code
- create needed Java source and resource files
- Build
- The toolkit compiles and preverifies Java source files
- Run
- The compiled Java class files are run on the emulator.
To make life easy we can lift the example from the Sun's User
Guide
Java Example //
from the Sun's User Guide
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class TinyMIDlet
extends MIDlet
implements CommandListener {
public void startApp( ) {
Display display = Display.getDisplay(this);
Form mainForm = new Form("TinyMIDlet");
mainForm.append("Welcome to the world of MIDlets!");
Command exitCommand = new Command("Exit", Command.EXIT, 0);
mainForm.addCommand(exitCommand);
mainForm.setCommandListener(this);
display.setCurrent(mainForm);
}
public void pauseApp () {}
public void destroyApp(boolean unconditional) {}
public void commandAction(Command c, Displayable s) {
if (c.getCommandType() == Command.EXIT)
notifyDestroyed();
}
}
1. Save Source
File
Notice the directory that the WTK saved to was way
inside the User's location on Windows.
Example Save Location
C:\Document and Settings\Peter\j2mewtk\2.5.2\apps\memos\src
//
the toolkit did not offer us options here
2.
Build
Click Build. If you have errors the build will fail.
Fix and try again!
3. Run
//
emulate
Choose the MIDlet to run in the
emulator. Clicking the
square button activates 'Launch'.
Full
Development Cycle
The full cycle is more complicated and includes the
following steps:
Edit source code > Package
> Install > Run
- Edit source code
- Package
- compiles and preverifies as before
- also bundles Java class and resource files
- creates the MIDlet suite in a JAR
- and a suite Descriptor
- Install
- MIDlet suites need to be installed before they can run
- You can install the MIDlet suite into:
- the Sun Wireless Toolkit for CLDC emulator
- or a real device.
- Run
- As in the simple development cycle
There are important differences between running an
installed application and running an application in the
simple development
cycle.
Packaging
To have the Toolkit package your MIDlet suite, choose:
Project > Package > Create Package.
The MIDlet suite descriptor and JAR file are generated
and placed in the bin directory of your project.
Here is the JAD File created for the a simple project
called Memos.
JAD File Created by Toolkit
MIDlet-1: Memos, Memos.png, Memos
MIDlet-Jar-Size: 923
MIDlet-Jar-URL: Memos.jar
MIDlet-Name: Memos
MIDlet-Vendor: Unknown
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.1
MicroEdition-Profile: MIDP-2.1
Here is the manifest that goes with the Jar Archive.
Generated Manifest File For Jar File
MIDlet-1: Memos, Memos.png, Memos
MIDlet-Name: Memos
MIDlet-Vendor: Unknown
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.1
MicroEdition-Profile: MIDP-2.1
Install
Proper testing of a MIDlet requires an install. When
a MIDlet is run in the emulator, it loads directly from
the class files and doesn't test the packaging.
OTA, Over the Air
To resemble how applications work on real devices,
OTA mode can be used.
To install applications in the Sun Java Wireless
Toolkit emulator, choose the following:
Running OTA
Project > Run via OTA.
The emulator window opens, but instead of running the
MIDlet directly, the emulator shows the Application
Management Software (AMS) welcome screen. This
software is like that which real devices must have to
manage MIDlet suites.
- Choose Apps
- Select Install Application
- Press the select button on the emulator.
- The emulator prompts you for the URL location
- // The URL is already completed for you.
- Choose Install at Confirmation
- Once installed select 'Launch'
The toolkit also allow you to
create a project from
a jar and jad file.
While there are many other features to explore
on the toolkit we have enough functionality to
facilitate programming MIDlets.
A final feature that is of interest to note now is the
obfuscator.
The
Obfuscator & ProGuard
The obfuscator is used to reduce the size of class files.
MIDlet suites have to be compact, both to minimize
download times and to meet JAR file size limits. The
obfuscator can be used at the packaging step.
The Sun Wireless Toolkit for CLDC doesn’t come with
an obfuscator but it is already configured to use the
ProGuard obfuscator. You will need to do is download
ProGuard and put it in a place where the toolkit can
find it. ProGuard is published under the terms of the
GNU General Public License (GPL). Agree to the
licence, and the download is free.
A Couple of Interesting First Observations
Following is a stripped down MIDlet pretty much
as small as it can get called MiniMidlet.
Minimal MIDlet Example
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class MiniMidlet extends MIDlet{
public void startApp() {
Display display = Display.getDisplay(this);
Form mainForm = new Form("TinyMIDlet");
mainForm.append
(
"******Hello Tiny********"
);
display.setCurrent(mainForm);
}
public void destroyApp(boolean unconditional){}
public void pauseApp(){}
}
Abstract Methods in Parent Have to be Overridden
Now if MIDlets were like applets we would
not need to explicitly override the destroyApp( )
and pauseApp() methods. Commenting them
out though indicate they are defined abstractly
in the parent class. Thus you see why they need
to be present even if they are not asked to do
anything.
MIDLET
Class
One of the key imports we have seen in all our
examples is the following:
Example
import javax.microedition.midlet.MIDlet;
If you look in that package there is the single class
MIDlet. It has a single protected no-args constructor
and the following methods.
MIDlet Methods //
from the J2ME Documentation
- int
checkPermission(String permission)
- get the status of the specified permission.
- protected abstract void destroyApp(boolean
unconditional)
- signals the MIDlet to terminate and enter the Destroyed
state
- String getAppProperty(String key)
- for retrieving named properties
- from the application management software
- void notifyDestroyed( )
- notifies the application management software it is
terminating
- void notifyPaused( )
- notifies the application management software the MIDlet
is paused
- protected abstract void pauseApp( )
- signals the MIDlet to enter the Paused state
- boolean platformRequest(String URL)
- requests that the device handle the indicated URL
- for example, to display or install the resource
- void resumeRequest( )
- used by MIDlet to indicate that it wants to enter the
Active state
- protected abstract void startApp( )
- signals the MIDlet that it has entered the Active state
Exceptions
MIDlet defines one exception, the MIDletStateChangeException
which is thrown by startApp( ) and destroy( ).
Here we see where some of the life cycle methods are
defined as abstract and require explicit overriding even
if just to stub the methods out.
Primitives
in MIDlets
The following example expands to include the use
of the different primitive values Java has to offer.
As well there is a couple System.out.println
statements.
Recall our primitives in Java are as follows:
Table showing the Basic Categories of Java
Primitives
Type |
Use |
boolean |
represents
truth values, true and false |
int,
long, byte, short |
Integral
Numbers { 1 , 2 , 3 } |
double,
float |
Real
( floating point ) Numbers { 1.1, 2.2,
3.3 } |
char |
represents
character data { 'A ' } |
A MIDlet with Primitives with
System.out Println Statement
import
javax.microedition.lcdui.*;
import
javax.microedition.midlet.MIDlet;
public class ME_Lang extends
MIDlet{
boolean boo=true;
byte b=32;
short s=32000;
char c='A';
int i=1299999;
long l =2999999999999L;
float f=3.2F;
double d= 12345.123456;
public void startApp() {
Display display =
Display.getDisplay(this);
Form mainForm = new
Form("TinyMIDlet");
mainForm.append
(
" Primitive
Types \n" +
"====================\n" +
"boolean: " + boo +
"\n" +
"byte: "
+ b + "\n" +
"short: " +
s + "\n" +
"char: "
+ s + "\n" +
"int: " + i + "\n" +
"long: "
+ l + "\n" +
"float: " +
f + "\n" +
"double: " +
i + "\n" +
"===================="
);
display.setCurrent(mainForm);
System.out.println("\nThe
console is represented by the WTK
screen!");
System.out.println("Add f
plus d : " + f + d +"\n");
}
//
destroyApp(boolean) is abstract and must be overridden
public void
destroyApp(boolean unconditional){}
//
ditto for
pauseApp()
public void
pauseApp(){}
}
Notice when the above code is run the System.out.println
print to the console of the WTK UI. That represents the
command line console.
All
Primitives Are Now Supported
A second point to note is that all the primitive types are
supported. Early on in MIDlet history, developers were
adviced not to use the float or double type as you could
not suppose that target devices would support these
types.
Clarification
CLDC 1.0 did not support floating point numbers however
CLDC 1.1 does and is what is supported in the WTK.
From the Sun Site
"CLDC 1.1 is a revised version of the CLDC 1.0
specification,
and includes new features such as floating point
and weak
reference support, in additional to other enhancements. CLDC
1.1 is backward compatible with CLDC 1.0,
and continues to
target small and resource-constrained devices with the objective
of maintaining a tight footprint."
- Sun
Site
Documentation
Characterizing the J2ME Environment
Anyone coming from a Java
Standard or Enterprise
environment immediately wants to know how they
will be impacted by the constrained environment of
the Micro world. First we may reiterate some of the
limitations imposed by the Micro JVM. Really the
limitations are not that bad and are often imposed
by security considerations.
Micro Java Virtual Machine
Constraints
- floating point support is added in CLDC 1.1
- some environments may not have it
- no finalization
- no finalize() method is available
- for cleaning up operations on data
- limited error handling // virtual machine level
- CLDC
- Errors
- Error
- NoClassDefFoundError
- OutOfMemoryError
- VirtualMachineError
- No JNI, Java Native Interface support
- because of security considerations
- and memory constraints, JNI is costly
- No User Defined Class Loaders
- the CLDC must have it built in
- another security consideration
- No support for reflection
- as a result no RMI Object Serialization
//
RIM's API supports a version of RMI
- No thread groups or daemon threads
- but does support multi-threading!
- has a Thread class
- weak reference support was added in CLDC 1.1
The
MIDP 2.1 API
What is impressive is the number of new APIs that are
have been added to augment the initially austere offering
made in MIDP. We saw the list of many above. The original
offering has been enhanced and is now available in the
MIDP 2.1 API .
Originally the API was a slimmed version of JDK1.2
packages, namely the following:
MIDP2.1 API Core Packages
- java.io
- java.lang
- java.util
In addition to these packages the
API is augmented
with the following packages which we investigate as
we proceed.
Additional MIDP2.1 Packages
- javax.microedition.io
- javax.microedition.lcdui
- javax.microedition.lcdui.game
- javax.microedition.media
- javax.microedition.media.control
- javax.microedition.midlet
- javax.microedition.pki
- javax.microedition.rms
Following are Classes that come down from java.lang.
Many of them are wrapper classes for the primitives.
There are the essential Math, String and StringBuffer
classes and Thread, System and Throwable.
The java.lang Package Classes
- Boolean
- Byte
- Character
- Class
- Double
- Float
- Integer
- Long
- Math
- Object
- Runtime
- Short
- String
- StringBuffer
- System
- Thread
- Throwable
There is a pretty good set of
Exception classes
you can refer to the API documentation to see.
There is one interface the 'Runnable' interface
needed for multithreading.
Following is a MIDlet that displays some of the
above noted classes in use.
Example
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class ME_MoreLang extends MIDlet{
public void startApp() {
Display display = Display.getDisplay(this);
Form mainForm = new Form("TinyMIDlet");
String statement1 = "The newer MIDlet API supports Wrapper
Classes";
Boolean booWrap= new Boolean(true);
String statement2 = "This is " + booWrap.toString() +
"\n";
String statement3 = "It does Math! The square root of 91 is " +
Math.sqrt(91) + "\n";
String statement4 = "It has a Throwable! Throw an Exception.";
String statement5 = catchIt();
mainForm.append
(
statement1 + "\n" +
statement2 + "\n" +
statement3 + "\n" +
statement4 + "\n" +
statement5
);
display.setCurrent(mainForm);
//
method that throws exception is called
catchIt( );
}
// exception
throwing method defined
String catchIt( ){
String catcher="";
try{
throw new
Throwable("Sinker!");
}
catch(Throwable t){
catcher=
"Not so fast " + t.getMessage();
}
return catcher;
}
//
destroyApp(boolean) is abstract and must be overridden
public void destroyApp(boolean unconditional){}
// ditto for
pauseApp()
public void pauseApp(){}
}
Again the IO package is trimmed but the key
classes are there for doing input and output.
We do not have a FileWriter or FileReader class
and can't expect to write to file. This of course makes
sense, when you think about the fact that a mobile
device like a cell phone will not have a file system,
at least not yet!
We see later the limited sort of storage that is
available on wireless devices later. We also see
different sorts of streaming connections that can
be made over networks using wireless devices.
The java.io Package Classes
- ByteArrayInputStream
- ByteArrayOutputStream
- DataInputStream
- DataOutputStream
- InputStream
- InputStreamReader
- OutputStream
- OutputStreamWriter
- PrintStream
- Reader
- Writer
Included in this package are five typical IO Exceptions
plus the DataInput and DataOutput interfaces.
The java.util Package Classes
- Calendar
- Date
- Hashtable
- Random
- Stack
- Timer
- TimerTask
- TimeZone
- Vector
The util package includes the Enumeration interface
and two exceptions, the EmptyStackException and
the NoSuchElementException.
Programming
Practices for the J2ME
Before getting into details of the different classes
of the API, we might consider some general good
programming practices. These are taken from 'Lurker's
Guide to Optimizing MIDP apps'. The article can be
found at the following site.
The Lurker's Guide to J2ME
http://www.blueboard.com/j2me/index.htm
Lurker see optimization possible for the following:
- maintainability
- speed
- size
Maintainability
Maintaining good organization, structure, and code readability
are important goals. A first practical tip made on the Lurker
site is to avoid creating more objects than are necessary.
- Avoid the Proliferation of Objects
Lurkers makes the point that objects are
allocated from runtime
memory which is a scarce resource. Primitive data types on the
other hand are allocated directly on the stack.
- Use StringBuffer rather than String
Another tip is to use StringBuffer rather than the String class.
In Lurker's example the String code is replaced with similar code
based on String buffer.
Lurker's String Example
String tempString="";
iceCreamGroup x=new IceCreamGroup();
for (int i=0;i<someNumber;i++) {
tempString+=x.getIceCream (i);
}
The Alternate StringBuffer Class
StringBuffer buff=new StringBuffer();
iceCreamGroup x=new IceCreamGroup();
for (int i=0;i<someNumber;i++) {
buff.append(x.getIceCream (i));
}
Speed
One has to assume that a hand-held device has a
slow processor.
An interesting point that is made at the Lurker's site
is that perceived speed is more important than the
actual time it takes to do something. Consider how
an hour glass symbol can make a wait seem OK!
If you have used loops in graphics you know they
can eat up processor power. The Lurker's site
suggests removing any unneccessary evaluations
from loops.
The Lurker's Example
for (int i=0;i<theVector.size();i++) {
Object x=theVector.elementAt(i);
}
// calculate Vector size( ) before using it in the loop
Alternative
int theSize=theVector.size();
for (int i=0;i<theSize;i++) {
Object x=theVector.elementAt(i);
}
- Use Arrays in Place of Vectors or HashTables
Another good tip, is to, where possible use arrays
instead of Vectors or HashTables. Underneath these
objects, arrays are used anyway so to escape the
overhead of the objects try to use arrays only.
A fifth rule Lurker's offers is to use local variables
instead of instance variables which take a little longer
to process.
Size
Phone companies will often impose size limits on
applications.
- Minimize the Number of Classes in the Jar
Lurkers suggest minimizing the number of classes in
your jar file. To quote "(a) Only include the classes you
need in your final jar, (b) consider removing "bells and
whistles" functionality, and (c) refrain from using inner
classes."
Lurker's seventh rule is to use the obfuscation function
to reduce the size of the download.
The final tip is to reduce the number an size of resource
files such as images.
Assignment
1 ) Run the Minimal MIDlet above. Comment out
each of the pauseApp( ) and destroy( ) app methods.
What is the error report given at the WTK console.
2) Create a new project with the WTK toolkit. You
may use the Primitive MIDlet above as a template.
a ) Comment out each of the pauseApp( ) and destroy( )
app methods. What is the error report given at the WTK
console.
b) Recreate the primitives output this time using wrapper
classes supplied in the API to wrap different values
that are good representatives of their types.
c ) Create a method in the MIDlet that uses the Date( )
or Calendar class to return the date.
3) Inside the Primitive MIDlet create a method that
returns the Date and call it within the output that is
put to the device screen.
Example
String td = " Time and Date " + myGetDateMethod( );
Read the following if you want or need a head start on
this.
Time Saving Tips
// You will probably use the Calendar class that you don't instantiate.
// Instead you use the getInstance( ) method. I then called getTime( )
// on the object. The method will be placed in the MIDlet at the same
// scope as the other methods. You will need to import the java.util package.
Example
import java.util.*;
class theTime {
public static void main(String [] args){
System.out.println("Day, Date, Time & Year: " + Calendar.getInstance().getTime());
}
}