J2ME – Java on the Mobile Phone

 

Before you start running your first Java program on your mobile device, we assume that you have java installed on your PC and you have downloaded J2ME from the sun site and installed it on your harddisk.

 

We then click on Start, Programs and then on J2ME Wireless Toolkit 2.0 Beta 2, followed by the icon KToolBar. This will execute a program ktoolbar.exe from the folder C:\WTK20\bin\. The executable is a program that will execute the compiled Java programs. The J2ME software, by default, gets installed in the WTK20 folder

 

To create a project, click on the big button New Project. A dialog box comes up with two questions, the first being the name of the project, we call it vijay and then the name of the Midlet class, in our case it will be zzz.

 

A Midlet is nothing but a Java program running on a mobile handset. Click on the OK button, which then leads on to another dialog box. Click on the OK button here and it will show some useful messages on the screen.

 

The first one reports the fact that the Java source files have been placed in the directory c:\WTK20\apps\vijay\src. Thus, every project has its own sub directory under the apps directory.

Off we proceed to this directory and to our surprise, though there is a directory created but there are no existing files within.

 

Create a text file called zzz.java using any word processor. The J2ME toolkit does not come with an environment to enable us to write code, hence we have to resort to our own word processor.

 

zzz.java

public class zzz

{

}

 

Save the file and then go back to the program KtoolBar. Here click on the button Build, which results in no errors. Now click on run. The outcome is that some mobile phone is seen with the name of our project vijay.

 

 


Thereafter, click on the soft button below the words Launch on the handset on the right hand side. This gives an error ‘Class not a Midlet’. On closing the handset, when we move back to KtoolBar, the same error is seen.


 

 


As mentioned earlier, a Midlet is nothing but a Java class but it is derived from the class MIDlet. Class zzz is a stand-alone class which must be derived from the MIDlet class.

 

Now add the following code to zzz.java.

 

zzz.java

import javax.microedition.midlet.*;

public class zzz extends MIDlet

{

}

 

The class MIDlet comes from the package javax thus denoting that the package is not part of the standard java packages, which usually start with java. Then microedition is indicative of the fact that the package deals with the mobile world and finally comes midlet.

 

Building or compiling the above program again gives an error now stating that the class MIDlet is an abstract class.

 

 

For those who arrived late to the party, an abstract class is an incomplete class thus it cannot be used in its own form. There is at least one function in this class marked abstract and it does not have a function body. Unless the code for the incomplete functions are not specified in the derived class, the class remains unusable.

 

On reading the documentation, we discovered the functions that required code and have inserted the same in the java file.

 

zzz.java

import javax.microedition.midlet.*;

public class zzz extends MIDlet

{

public void destroyApp(boolean unconditional)

{

System.out.println("destroyApp");

}

public void startApp()

{

System.out.println("startApp");

}

public void pauseApp()

{

System.out.println("pauseApp");

}

}

 

Finally, build the class zzz and it generates no errors. This also is conclusive of the fact that the class MIDlet has 3 abstract functions, startApp, pauseApp and destroyApp. The println function is used to notify when the above functions get called.

 

The above program when launched also does not show any errors but no significant output is witnessed on the mobile screen.  However, the KtoolBar console displays startApp. This could possibly happen only if the first method to be called from our MIDlet is startApp. Also, when the mobile handset is closed, the method destroyApp is seen being called.

 

 

zzz.java

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public class zzz extends MIDlet

{

Form mForm;

public void destroyApp(boolean unconditional)

{

System.out.println("destroyApp");

}

public void startApp()

{

System.out.println("startApp");

mForm = new Form("Vijay & Sonal");

Display mDisplay;

mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mForm);

}

public void pauseApp()

{

System.out.println("pauseApp");

}

}

 

The above example sincerely changes the title of the form to Vijay & Sonal.

 

Lets us unravel this secret now. In the above program, mForm is an instance variable of the class Form. The Form class is always used when interacting with the user and an instance variable is used so that others functions too can use this variable. All initialization or one time code is placed in the method startApp. The text given to the constructor when creating a new Form object gets displayed as the title of the form. Thus the handset shows Vijay & Sonal.

 

In the J2ME world, the display is the highest object that is to be worked with. The static function getDisplay from the Display class returns the current display. Then the setCurrent method is used from the Display object to set the form to mForm, i.e. superseding the default form with the user-created form.  The Form and Display class belong to the package lcdui.

The next program is a midlet that interacts with the user.

 

zzz.java

public void startApp()

{

System.out.println("startApp");

mForm = new Form("Vijay & Sonal");

mForm.append("Hi");

Display mDisplay;

mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mForm);

}

 

 

The method startApp is the only function put up for display since most of the code remains the same. As before, a new Form called mForm is created . The method append from the Form class is put to use to adds a string to the displayed form. That’s it.  It’s that easy to emit out things on the handset !!!

zzz.java

 

public void startApp()

{

Command mCommand;

System.out.println("startApp");

mForm = new Form("Vijay & Sonal");

mForm.append("Hi");

mCommand = new Command("Quit", Command.EXIT, 0);

mForm.addCommand(mCommand);

Display mDisplay;

mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mForm);

}

 

The next task on the agenda is to create a soft button on the mobile handset like the Launch soft key. For this reason, the class Command is used since it enables creating such soft keys.

 

The constructor is given three parameters.

The first is the text the user should see,  and in our case the string is Quit.

The second parameter is the intent of the soft key. J2ME has 8 predefined types BACK, CANCEL, EXIT, HELP, ITEM, OK, SCREEN, and STOP. This is more of a guide to the user interface of the mobile so that it can handle the Back soft key in its own way that the user is familiar with.

The last is a priority where 1 denotes highest priority. The basic intention behind this option is that if the handset can display only 2 soft keys whereas the code has 4, then only the higher priority gets displayed.

 

Finally, the Form object mForm’s method addCommand is used to add this button to the form.

 

zzz.java

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public class zzz extends MIDlet implements CommandListener

{

Form mForm;

Command mCommandQuit;

Command mCommandItem;

public void startApp()

{

System.out.println("startApp");

mForm = new Form("Vijay & Sonal");

mForm.append("Hi");

mCommandQuit = new Command("Quit", Command.EXIT, 0);

mCommandItem = new Command("Choose", Command.ITEM, 0);

mForm.addCommand(mCommandQuit);

mForm.addCommand(mCommandItem);

Display mDisplay;

mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mForm);

mForm.setCommandListener(this);

}

public void destroyApp(boolean unconditional)

{

System.out.println("destroyApp");

}

public void pauseApp()

{

System.out.println("pauseApp");

}

 

public void commandAction(Command c, Displayable s)

{

System.out.println("commandAction");

notifyDestroyed();

}

}

 

The above example has two buttons Quit and Choose that come at the bottom of the screen.

 

In the program, class zzz implements the interface CommandListener. This interface has only one method commandAction. Each time any of the soft keys is clicked on, this method gets called.

 

The method setCommandListener is passed the parameter ‘this’ to specify that the current class contains the commandAction method. Finally, the println method reconfirms that the two soft keys call upon this method.

 

The method notifyDestroyed gets called whenever we exit from the handset.

 

zzz.java

public void commandAction(Command c, Displayable s)

{

System.out.println("commandAction");

if ( c == mCommandQuit)

notifyDestroyed();

if ( c == mCommandItem)

mForm.append("Bye");

}

 

 

The above example deciphers the soft key chosen by the user. The first parameter is a Command object that decides on the soft key that was chosen. The action to be taken up depends upon the programmer which he can safely enclose within the if statements.

 

zzz.java

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public class zzz extends MIDlet implements CommandListener

{

Form mForm;

Command mCommandQuit;

Command mCommandItem;

TextField mTextField;

public void startApp()

{

System.out.println("startApp");

mForm = new Form("Vijay & Sonal");

mCommandItem = new Command("Choose", Command.ITEM, 0);

mForm.addCommand(mCommandItem);

mTextField = new TextField(null, "Vijay Mukhi", 100, TextField.ANY);

mForm.append(mTextField);

Display mDisplay;

mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mForm);

mForm.setCommandListener(this);

}

 

public void destroyApp(boolean unconditional)

{

System.out.println("destroyApp");

}

public void pauseApp()

{

System.out.println("pauseApp");

}

public void commandAction(Command c, Displayable s)

{

System.out.println("commandAction");

String mstring = mTextField.getString();

mForm.append(mstring);

}

}

 

This example delves further on the interactivity issues where the user can now enter some text in a textbox.

The class TextField takes 4 parameters. The first is the label a string and the second is also a string, the initial string the user will see. Thus running the midlet shows vijay Mukhi. The third is the maximum number of characters that can be entered in the text box and the last is the constraints that can be imposes on the date entered by the user. An entire volume can be written on the constraints that can be applied to the input which can range from simple things like checking for numbers to complex checks like phone numbers.

 

The Form class is then used to add or append the TextField to the Form and then a Command object is added to the form.

 

On executing the program at first, the string vijay Mukhi is seen in the text field. Then we can make the changes we want in the handset and then choose the soft button.

 

This calls the method commandAction which in turn uses the getString method of the TextField to retrieve the string the user keyed in. This string is then added to the form so that the TextField now display the string keyed in by the user.

 

zzz.java

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

public class zzz extends MIDlet implements ItemStateListener, CommandListener

{

Display mDisplay;

Form mForm;

Command mCommand;

ChoiceGroup mChoiceGroup;

public void startApp()

{

mDisplay = Display.getDisplay(this);

mChoiceGroup = new ChoiceGroup("Vijay Mukhi", Choice.EXCLUSIVE);

mChoiceGroup.append("First", null);

mChoiceGroup.append("Second", null);

mChoiceGroup.append("Third", null);

mChoiceGroup.setSelectedIndex(1, true);

mCommand = new Command("View", Command.SCREEN,2);

mForm = new Form("Exclusive ChoiceGroup");

mForm.append(mChoiceGroup);

mForm.addCommand(mCommand);

mForm.setCommandListener(this);

mForm.setItemStateListener(this);

mDisplay.setCurrent(mForm);

}

public void commandAction(Command c, Displayable s)

{

int i = mChoiceGroup.getSelectedIndex();

String ss = mChoiceGroup.getString(i);

System.out.println("You selected: " + ss);

}

public void itemStateChanged(Item item)

{

System.out.println("Inside itemStateChangeds()");

}

public void destroyApp(boolean unconditional)

{

System.out.println("destroyApp");

}

public void pauseApp()

{

System.out.println("pauseApp");

}

}

 

The above program displays a list of radio buttons with the second option being shown selected.

 

To display radio buttons on the screen, the ChoiceGroup class is used.  The constructor  is given the heading of the radio buttons as the first parameter and the second parameter restricts the choice to only one option at a time. There are multiple other options where multiple options can be selected. Then three options are added to the choice group using the append method.

 

This method takes two parameters, the first is a string and the second is an image, if supported. The selected radio button is then set using the setSelectedIndex method.

 

In computer programming, the count always starts at 0 and not 1. The second parameter is set to true and hence the radio button option is shown selected , false deselects it. Then a command and a form object are created. The command and ChoiceGroup are then added to the Form object using the same append method. The Forms append method requires an Item object, and all UI widgets are derived from the Item class.

 

Then two listeners, the CommandListener and the ItemListener are added.

 

The class zzz also implements the ItemStateListener. This listener has only one method called itemStateChanged.

 

The setItemListener method in the Form class is used to call the above method each time the state of the Choice Groups items is changed. The change can be brought about by using the big arrow keys on the mobile phone . The Select button can then finally be used to select the final item.

 

This act of ours calls the method itemStateChanged. The soft button View shows the Choice Group selected. The Choice Group has a method getSelectedIndex that returns the index of the selected item. This number when given to the getString method returns the string of the selected item.

 

mChoiceGroup = new ChoiceGroup("Vijay Mukhi", Choice.MULTIPLE);

 

In the next example, make two changes as shown above. Firstly, change the second parameter of the ChoiceGroup constructor to MULTIPLE from exclusive. This results in check boxes being displayed instead of radio buttons.

 

public void commandAction(Command c, Displayable s)

{

boolean selected[] = new boolean[mChoiceGroup.size()];

mChoiceGroup.getSelectedFlags(selected);

for (int i = 0; i < mChoiceGroup.size(); i++)

System.out.println(mChoiceGroup.getString(i) + (selected[i] ? ": selected" : ": not selected"));

}

 

Now that multiple options can be selected, the following changes are recommended in the commandAction method.

 

The size method of the ChoiceGroup gives a count on the choices or items present in the Choice Group. So in the program, we create an array of boolean using this number, which in our case is three.

 

The getSelectedFlags method either return true or false. This function is put to use to fill up this boolean array. We then use a for loop  to display the text of the choice item like before and the selected array to display selected or not selected depending upon every individual member.

public void startApp()

{

mForm = new Form("");

mDisplay = Display.getDisplay(this);

try

{

Image im = Image.createImage("/Theme-1.png");

mForm.append(new ImageItem(null, im, ImageItem.LAYOUT_CENTER , null));

mDisplay.setCurrent(mForm);

}

catch (java.io.IOException e)

{

System.err.println("Unable to locate or read .png file");

}

}

 

This example comes as a relief from the earlier ones. It simply displays an image on the handset. This image is a png file, which is situated in the res directory under vijay.

 

 

The Image class has a static method createImage that is passed the image file name. Then the ImageItem class is used to specify other parameters like the layout and then this ImageItem object is added to the form.

 

zzz.java

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

import java.util.*;

public class zzz extends MIDlet

{

Display mDisplay;

public void destroyApp (boolean unconditional){}

public void pauseApp () {}

public void startApp ()

{

mDisplay = mDisplay.getDisplay(this);

Form mForm = new Form("Change Date");

java.util.Date now = new java.util.Date();

DateField dateItem = new DateField("Today's date:", DateField.DATE);

dateItem.setDate(now);

mForm.append(dateItem);

mDisplay.setCurrent(mForm);

}

}

 

The outcome of the above program simply displays today’s date, This happens due to the DateField object created in the program. This object is created by specifying some text that is to be used as a label. The second parameter is the mode that is a Date and not time.

 

The date is set to todays date using the Date class from the java.util namespace. The setDate method from the DateItem class performs this task for us. Once again, this object is added to the form.

 

Thus on clicking the Select button, a calendar gets displayed. Change the month or year to what suits you and then click on the soft button save. After clicking on save the date changes. Bear in mind that we have not written any code for any of this to happen.

 

zzz.java

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

public class zzz extends MIDlet

{

Display mDisplay;

public void destroyApp (boolean unconditional){}

public void pauseApp () {}

public void startApp ()

{

mDisplay = Display.getDisplay(this);

yyy canvas = new yyy();

mDisplay.setCurrent(canvas);

}

};

class yyy extends Canvas

{

public void paint(Graphics g)

{

}

protected void keyPressed(int keyCode)

{

if (keyCode > 0)

System.out.println("keyPressed " + ((char)keyCode));

else

System.out.println("keyPressed action " + getGameAction(keyCode));

                

}

};

 

This example enlightens the user on the key s/he has pressed.

In place of the Form class that has been used extensively earlier on, we now use a Canvas object. This object gives access to the low level events and graphics.

The class yyy extends the Canvas class and the setCurrent method uses this object. The canvas class has a method paint that gets called whenever the screen is to be redrawn, similar to an applet.

 

The keyPressed method gets called whenever any key is pressed. If we press the first three keys, we see 1 2 and 3. But when we press the right arrow, the keycode is less than zero and the getGameAction is 5. This thus helps in figuring out the key that has been pressed.

 

zzz.java

import java.io.*;

import javax.microedition.io.*;

import javax.microedition.lcdui.*;

import javax.microedition.midlet.*;

public class zzz extends MIDlet

{

Display mDisplay;

public void startApp()

{

mDisplay = Display.getDisplay(this);

try

{

StreamConnection c = null;

InputStream s = null;

StringBuffer b = new StringBuffer();

TextBox t = null;

c = (StreamConnection)Connector.open("http://localhost/a.txt");

s = c.openInputStream();

int ch;

while((ch = s.read()) != -1)

{

b.append((char) ch);

}

t = new TextBox("Vijay", b.toString(), 1024, 0);

mDisplay.setCurrent(t);

}

catch (IOException e)

{

System.out.println("IOException " + e);

}

}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

}

 

a.txt

vijay

sonal

 

The objective of this last example is to retrieve some data off a web site.

 

The display object is always thereas before. Then a StringBuffer object is created to hold the data from the web site. The static function ‘open’ from the Connector class is given the URL, the site address from where the data is to be retrieved. This gives a connection to the web server.

 

The next job is to read off this connection and for this purpose, an InputStream object is required. This can be achieved by using the openInputStream method of the StreamConnection class.

 

Finally the read method of the stream is used to read one char at a time. A while loop is used to read all the data characters which eventually is stored in the StringBuffer object using append.

 

When the loop terminates, the entire data from the web site is assumed to have been received therefore, we create a fresh text box with this data. In this example, we have not used the Form or Canvas but the TextBox for the setCurrent function. The end result is the text vijay and sonal being displayed in the text box, as these words are contained in the file a.txt.