[ZOIS] Home Page * Contact ZOIS * Technical Notes

Writing a Java Program for a Mobile Phone

ZOIS Technical Note TN-2009-10-01.

Author and Audience

A small program was written for a Mobile Phone using the Java programming language as a test piece. This TN describes the experience. A general knowledge of Java and UNIX style operating systems is assumed. Written by Martin Sullivan[1], ZOIS Limited, Cockermouth.

Abstract

It was decided to explore the programming of mobile devices and in particular Mobile Phones using the widely available J2ME platform[2]. An existing Clock Application[3] designed to run on Java-enabled browsers was chosen as a test piece. Problems were noted in the use of floating point variables, multi-tasking and Internet communications, which were overcome and are explained.

Introduction

[Picture: Clock Midlet on Phone]

A screenshot of the ZoisClock midlet in the J2ME mobile phone emulator

Java Virtual Machines (JVM) are now ubiquitous on Mobile Phones and machines of that ilk. They allow pre-compiled Java bytecode programs to run on these restricted platforms with a limit storage capacity and some Internet connectivity. It is thus possible to program the Mobile Phone to perform a wide variety of potentially distributed tasks. To practically explore how this was done a number a small program were written, with one in particular demonstrating a number of pit-falls that need to be know about if more complexed task-specific systems are to be written. The program written for this was a clock (ZoisClock), for the Author had already written just such a program as an Applet and was thus familiar with the source code. It would also give an indication of how difficult porting an existing Application would be.

In addition to simply displaying the time the ZoisClock gets the time from a time server remotely using the Internet and stores it as offset with respect to the Phones internal time.

The clock also provided a number of challenges both to be explored on this limited platform.

Materials and Platform

The basic development platform was Emacs on Linux (the author is over 50). The Java thus produced was compiled with the J2ME Wireless Toolkit[4], rather than using odd libraries and a complicated class-path. The J2ME WTK is documented elsewhere but contains all that is necessary to produce working packaged Midlets as such Java Byte Code programs for Mobile platforms are called. It also contains an number of Phone emulators that allow testing and experimentation of code without the necessity of physically installing it on a Phone.

Method

Basic J2ME (as found on all J2ME Phones) conforms to the Mobile Information Device Profile (MIDP) 1.0[5] and Connected Limited Device Configuration (CLDC) 1.0[5] does not have floating-point types, a conclusion which is both strange and non-obvious, since even 70's-era programmable calculators had the ability to deal with numbers in the continuum. That needs to be re-iterated, Java on Mobile Phones doesn't have Floating Point. A Fixed-point decimal version of sine was therefore written following the algorithm found in a on-line Java based CS course[7].

The necessary calculations were performed in Java int, with a fixed point notation that tripped over precision, anything more than 3 gives problems with integer overflow (1000 == 1.0). This leads to the following necessary assumptions Java int is really 16 bits (on J2ME MIDP 1.0 anyhow) and overflows are silently ignored (including possibly setting the sign-bit). It's all very PDP-8 assembler mid-70s with a Object Oriented high-level veneer (public class Stupid extends Bogosity implements Stupidity &c. &c.).

Here is the code use for calculating sine and cosine. The sine function uses an algorithm that calculates successive terms in a Taylor series based on the previous term. The calculation stops when the term returns a value which is integer 0 in this system (actually less than plus/minus 0.001 in real terms). Cosine is easily calculated in terms of sine.

 // Math class seems to be a problem on MIDP 1.0/CLDC 1.0, not only 
 // no PI, but also no sin() or cos(). And woopse, we don't have float
 // nor double either, so lets do everything in fixed point decimal, 1000
 // == 1.0 &c. Yes, I know about MathFP, but this is an intellectual
 // challenge I can't ignore.

 int sin (int x) {	   // compute the Taylor series approximation
     x %= (2 * PI);        // PI declared elsewhere to be 3141

     int term = 1000;      // ith term = x^i / i!
     int sum  = 0;         // sum of first i terms in taylor series

     for (int i = 1; term != 0; i++) {
        term = ((term * x) / i) / 1000; // has to be phrased
                                        // like this to preserve
                                        // precision.
        if (i % 4 == 1) 
            sum += term;
        if (i % 4 == 3) 
            sum -= term;
        } // for
	return (sum);
    } // sin


 int cos (int x) {
     x %= (2 * PI);
     return (sin ((PI / 2) - x));
 } // cos

The ZoisClock midlet uses the Internet to ensure that the time it returns is accurate. It uses the Phones internal clock and an offset to calculate the true time. This fragment uses an RFC 686 time service for simplicity and it is realised that this is now very much depreciated in favour of NTP. The following is an idealise fragment, the real code contains timeout handling, which here has been elided for clarity.

 long ticks = 0L;
 int buff[] = new int[4];
 int ix;

 StreamConnection connection = null;
 InputStream inputStream = null;
 DataInputStream dataInputStream = null;
 String timeServer = null

 try {
     timeServer = new String (getAppProperty ("TimeServer"));
 } catch (Exception e) {}

                            // provide 'time' even if nobody else does
 if (timeServer == null)
     timeServer = new String ("home.zois.co.uk"); 

 try {

     connection = (StreamConnection) Connector.open ("socket://" +
						      timeServer +
						      ":37", 
						      Connector.READ, true);
						     
				// RFC 868, 'cos it's easy and it's TCP.
				// Yep, should do it using NTP/SNTP, but
				// so what ...
     inputStream = connection.openInputStream ();
     dataInputStream = new DataInputStream (inputStream);
	    
	    			// A 32bit unsigned number in NBO (most
				// significant byte arrives first). We
				// have to be circumspect about sign ...
     for (ix = 0; ix < buff.length; ix++)
	 buff[buff.length - ix - 1] = 
		 dataInputStream.readUnsignedByte ();
	    // for 32bit NBO read buff.lenght is 4

     dataInputStream.close ();
     inputStream.close ();
     connection.close ();
 } catch (Exception e) {}

 for (ix = 0; ix < buff.length; ix++)
     ticks += ((long) buff[ix]) << (ix * 8);
 
 if (ticks != 0L) 	// got time
     adjust = ticks 
		- SINCE_1900 
		- (System.currentTimeMillis () / 1000L);

		      // The following lines adjust the display 
		      // suitably.
 screen.notify ("Adj: " + 
		       (adjust - screen.getAdjust ()) + 
		       "s");
 screen.setAdjust (adjust);

The above fragment naively assumes no consequence for a protracted Internet connection. In reality the acquisition of time from the Internet requires that this code be run with in a separate thread of control with an suitable mechanism that allows timeouts, lest this thread run for ever. In the ZoisClock this is achieved by having two threads using Thread. The first thread is relatively conventional and, in essence, jackets the above code. The second thread is started contemporaneously and executes Tread.sleep to implement a delay, then forcing the first thread to close.

In normal Java programming environments such thread programming would be relatively straight forward. The threads would coordinate using Thread.cancel, the first cancelling the second when it completed retrieving the time, the second cancelling the first should a time-out occur. In this environment, however, Thread.cancel is unavailable and threads are required to cooperate with each other through the medium of intermediate common variables. They can yield control through Thread.yield calls. Since one of the threads will be running independently, awaiting a response from the Internet at large, and not able to periodically monitor some variable, it was decided to terminate it by forcing an I/O exception artificially. The second timeout thread then looks something like this:

 public void run () {

     for (int ix = 0; ix < timeout; ix++) {
         try {
             this.sleep (1);
         } catch (InterruptedException ie) {
         try {
             connection.close (); // Force an IOException elsewhere
         } catch (Exception e) {} // ignore it here.
     } // try
     if (timeout == 0)
         return;         // timeout cancelled

     } // for
     try {
         connection.close (); // force an IOException, but ignore
                                 // it here, right?
     } catch (Exception e) {}
 } // run

In the above the timeout variable is shared between the two threads and can be set to zero to cause the timeout thread to terminate early.

This all makes for messy code with a variety of codependencies between the two threads and the main body of the program. It appears to work however, in a series of not very full artificial tests and live.

Once an offset to the Phones internal clock has been acquired it can be stored for future use, so that the ZoisClock is always displaying an accurate time without reference to the Internet. The J2ME Record Management Store system is a 'slotted' store associated with a single Midlet (although that has evolved). The individual records are enumerated and thus relatively sophisticated list and tree like structures can be built, together with what looks like an ISAM like direct access capability. For the ZoisClock however a single record with a long clock adjustment was all that was required:

 void writeAdjustment (RecordStore adjustStore, long adjust) {

     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     DataOutputStream outputStream = new DataOutputStream(baos);

     try {
         outputStream.writeLong (adjust); // Push the score into a
                                          // byte array.
         byte[] b = baos.toByteArray();
         if (adjustStore.getNumRecords () < 1) // new store
             adjustStore.addRecord (b, 0, b.length); // add
         else
             adjustStore.setRecord (1, b, 0, b.length); // update

     } catch (Exception e) {
     }
 } // writeAdjustment

 long readAdjustment (RecordStore adjustStore) {

     if (adjustStore == null)
         return (0L);

     long suggested = 0L;

     try {
         ByteArrayInputStream bais =
             new ByteArrayInputStream (adjustStore.getRecord (1));
         DataInputStream inputStream = new DataInputStream (bais);

         suggested = inputStream.readLong ();

     } catch (Exception e) {
     }

     return (suggested);
 } // readAdjustment

The chief finding when using this record store is that the initial, the first record is enumerated as '1'. This was counter intuitive, for most modern programming languages start array-like structures with index '0'.

Debugging can proceed symbolically (using jdb) running the following command:

jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=5000
having run Project > Debug in ktoolbar, as the controlling User Interface of the J2MEWTK is called. This seems to be fragile and a lot of time is spent stumbling around in the debugger trying to work out what it's doing, nothing new there then. Eventually external test-harnesses and println were used to bag the last faults, integer overflows, traditionally not something that symbolic debuggers have excelled at.

As ever, the Internet is your friend, The User Interface (UI) Class documentation is found on the Sun web-site[8] and a restrictive set of OS Classes (CLDC 1.0) are found there[9].

Discussion

There are many different platforms that constitute J2ME (now apparently to be called JME) this has resulted in sites such as MobileZoo[10] which aims to provide a break-down of which phones do what. A set of related Midlets would result which would have different levels of functionality and be targeted at various phones. It would seem safe to assume, however, that one should code to the absolute lowest common-denominator of platform and to use 'features' sparingly. A three year old S40 based 'smart' phone (Nokia 8260) only supports CLDC 1.0, with, of course a whole bunch of Nokia's own extensions.

That there was no floating point representation was found out only gradually, for the later versions of J2ME (MSA 1.0 for example) will allow float/double, and thus programs using them will work in the emulator. You'll also get quite a way down the build phase before you see a whinge about floating point constants not being allowed. The J2ME (CLDC 1.0) class java.lang.Math gives some clues, for it doesn't have things like trigonometry and square-root in it. This leads you to write buggy versions of sine and cosine functions before the penny drops. It's worth noting that Java traditionally emulated Floating Point operations, ignoring any standard hardware (and was therefore slow)[11].

As the lack of floating point and accompanying mathematics has caused problems to others who have therefore produced a floating point Class (complete with a set of attendant mathematical functions). MathFP seems to be the widest known[12]. It was decided, however to implement a private solution which addressed only the issues found in the ZoisClock.

After being challenged by a family member, Internet connectivity in the form of a function button was added. This caused the Midlet to go off and get the Internet time. A little calculation later and this caused the displayed time to be adjusted (the real clock in the phone could not be altered but the offset could be stored). Since the acquisition of information from the Internet can take some time this must proceed within a separate thread of control. Further to allow a time-out, a another independent thread of control must be used. The production of this new functionality proved challenging, the java.lang.Thread package for this version of Java doesn't allow cancellation, interrupt or stop. It was therefore necessary to have a time-out thread which tried to force an I/O error to get an exception thrown in the thread which does the actual network-read.

The clock was installed on the ancient Siemens SL55 Phone and found to work after a fashion. So the conservative coding to old standards was vindicated.

To get your version of the ZoisClock, download the following JAD and JAR files into your Phone using either an off-line method such as USB, Bluetooth or InfraRed or directly into the Phone using your favourite mobile browser. Be warned that you'll almost certainly be charged for the later, and some Phones will only support this method (for example Samsung's). The whole thing is highly make and model dependent so consult your documentation. Tradition has it that you need both files, but in most instances the JAR is all that is required. The ZoisClock Midlet has not been signed or obfuscated:

JAR * JAD

The format of JAD and JAR files, themselves, are explained elsewhere[13].

References

References found in this section, and in particular the HTML links were correct at time of writing (2009-12-01).

1. Martin Sullivan:
http://www.zois.co.uk/people/martin_sullivan
2. Java 2 Mobile Edition (J2ME):
http://java.sun.com/javame
3. A Java Clock and Some Lossages:
http://www.zois.co.uk/java/clock.html
4. Sun Java Wireless Toolkit for CLDC:
http://java.sun.com/products/sjwtoolkit
5. JSR 037: Mobile Information Device Profile for the J2ME Platform:
http://jcp.org/en/jsr/detail?id=037
6. JSR 030: J2ME Connected, Limited Device Configuration
http://jcp.org/en/jsr/detail?id=030
7. Introduction to Programming in Java:
http://www.cs.princeton.edu/introcs/home
8. Package javax.microedition.lcdui:
http://java.sun.com/javame/reference/apis/jsr037/javax/microedition/lcdui/package-summary.html
9. CLDC Library API Specification:
http://java.sun.com/javame/reference/apis/jsr030
10. MOBILEZOO: "The Definitive Museum for Mobile Diversity":
http://mobilezoo.biz
11. SDN Bug Detail: "native libraries for java.lang.Math should be non-strict":
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5005861
12. MathFP:
http://home.comcast.net/~ohommes/MathFP
13 JAD (file format):
http://en.wikipedia.org/wiki/JAD_(file_format)

$Date: 2010/02/22 16:37:29 $


Break Frame * E-mail Webmaster * Copyright