IBM Skip to main content
Search for:   within 
      Search help  
     IBM home  |  Products & services  |  Support & downloads   |  My account

developerWorks > Wireless | Java technology
developerWorks
Writing in EPOC
code1,952 KBe-mail it!
Contents:
An overview of Java on Symbian OS
Sample application: code analysis
Building the application
Running the application
Conclusion
Resources
About the author
Rate this article
Related content:
J2ME grows up
Subscriptions:
dW newsletters
dW Subscription
(CDs and downloads)
Build Java apps, like an EPOC-based phone, for the Symbian OS

Level: Intermediate

Naveen Balani (mailto:naveenbalani@rediffmail.com?cc=&subject=Writing in EPOC)
Technical Analyst, Syntel India, Ltd.
1 August 2002

EPOC-based devices running the Symbian OS, like Nokia's 9200-series phones, are popular worldwide, and they represent a potentially powerful application platform. Here, Naveen Balani walks you through the construction of a PersonalJava application that will run on such a Symbian OS device. You'll see by example how your Java skills can easily be turned to the construction of useful applications for phones and handhelds.

This article will help you write Java applications on EPOC-based devices. We will build a Java application that accesses a database of contact information and deploy and test the application on a Nokia-based emulator. To run the sample application, you'll need the Nokia 9200 Communicator Series SDK for Symbian OS (see the Resources section below for this link and other useful information). This article assumes that you are familiar with Java Swing programming, and gives you a brief introduction to the JavaPhone 1.0 APIs, which give Java programs access to a selection of native services on the phone used by our application.

An overview of Java on Symbian OS
The basis of the Symbian OS Java environment is the PersonalJava Application Environment, which implements version 1.1.1 of Sun's specification; it is partly based on legacy code from Symbian's Version 5 Java Runtime environment. Symbian OS also provides an implementation of the JavaPhone 1.0 set of APIs, which gives Java programs access to a selection of invaluable native services on the phone. These include:

  • Java Telephony API: Allows Java programs to create and terminate outgoing calls, listen for and answer incoming calls, and detect changes in the call state.
  • Calendar and Address Book API: Allows Java programs to read, write, and modify contact details, calendar items, and to-do items, working transparently with data in native Symbian format. We will be using the contact book APIs to store and retrieve our application information.
  • javax.comm : Allows Java programs to discover, configure, send, and receive data on available ports (serial and infrared).
  • P2P Wireless Datagram API: Allows Java programs to exchange datagrams with other devices via UDP or SMS.

We can test the application we develop here on an emulator before deploying it to an actual device. As noted, we will be using the Nokia 9200 Series Symbian OS SDK (Java edition), which can be downloaded from the Forum Nokia Web site (see Resources). The SDK includes an emulator, the PersonalJava application environment, tools, and utilities to deploy and run the applications.

Building Java apps on the Symbian platform
Let's take a look at the high-level steps required to build a Java application on the Symbian platform:

  1. Write the Java code in your favorite editor.
  2. Compile the code to Java class files.
  3. Create the <APPNAME>.txt and <APPNAME>.aif support files. (These are needed if you want the application to appear on the phone's extras bar and to have its own icon on the phone's screen.)
  4. Test under the WINS emulator (this requires a PC running Windows 95/98/NT/2000).
  5. Copy the class, .txt, and .aif files to the target machine. The class files do not have to be recompiled.
  6. Test your application on the device.
  7. Create an SIS installation file for easy deployment of your application.

We'll be following the first four steps in the list to develop our sample application. For more on deploying the completed app to a real Symbian OS device, see Resources.

Introduction to the Java Phone APIs
As our application relies on the Java Phone APIs for storing data in Symbian format, we'll look at some of them, namely javax.pim.addressbook and javax.pim.database, before going into the details of our code. Using these APIs, we can store and retrieve our contact information.

The ContactDatabase class is an abstraction modeling a database storing contact information. ContactDatabase implements the javax.pim.database.Database interface and stores information associated with contacts. This information is organized in the form of Items. A ContactCard, which stores information about an individual contact, is a subclass of Item that can be retrieved from the ContactDatabase.

To open the contact database, we can use the static method ContactDatabase.openDatabase(). After we've opened the database, we can manipulate it. Each row of a database corresponds to a ContactCard object. This object stores details of a contact in ItemFields, which can be aggregated further to produce AggregateFields.

The ContactDatabase class has static final fields that correspond to the name and value fields (and parameter name and parameter value fields) of the vCard specification (see Resources). If a field in the vCard specification has property named N, then the ContactDatabase will contain a static String field called N. The ItemFields of ContactCard map to these fields. Hence, the ContactCard equivalent field to the vCar property named N will be a static String field ContactDatabase.N.

For example, a few of the fields in the ContactDatabase class are listed below:

  • public static final java.lang.String N
  • public static final java.lang.String FN
  • public static final java.lang.String TEL
  • public static final java.lang.String ADR

These specify name, formatted name, telephone number, and structured delivery address, respectively.

A field such as ContactDatabase.N can be an aggregate composed of up to five parts, as follows, where the integer represents the index of the respective component part.

  1. FAMILY_NAME
  2. GIVEN_NAME
  3. ADDITIONAL_NAMES
  4. PREFIXES
  5. SUFFIXES

These part values are defined as fields of ContactDatabase. For instance:

Listing 1. Defining the fields of ContactDatabase


public static final int FAMILY_NAME

is the index in the N field of the family name (and has the value 0). Similarly:

Listing 2. Defining more fields


public static final int GIVEN_NAME

is the index in the N field of the given name (and has the value 1).

An ItemField can have a parameter value associated with it. A parameter has a name and a value. In a ContactDatabase the name is always TYPE:

Listing 3. Naming a parameter


public static java.lang.String TYPE

Some example values are given below in Listing 4.

Listing 4. Further example values


public static final java.lang.String HOME
public static final java.lang.String WORK

The values are all TEL field TYPE parameter values referring to home and work numbers, respectively. Similarly, Listing 5 includes some of the parameter values associated with an ADR field:

Listing 5. Parameter values associated with ADR


public static final java.lang.String HOME
public static final java.lang.String WORK

These indicate home and work addresses, respectively. We will be using the above fields while building our Java phone book application.

A record is inserted into the contact database in the form of contact cards. The contact cards contain ItemFields or an AggregateField. This can be added by using the contactCard addItem() method:

Listing 6. Inserting a new record


ContactCard contactCard = new ContactCard();
ItemField name = new ItemField(ContactDatabase.N, "Value");
contactCard.addItem(name);

To retrieve the data, we could use the items() method of the ContactDatabase to search for a particular record:

Listing 7. Searching for a record


private ContactDatabase addressbook;
Iterator result = addressbook.items(ContactDatabase.N, "Value To Search");

After getting the result, we could get each record as follows (we'll use ContactCard as our example):

Listing 8. Getting each record


ContactCard contact = (ContactCard)(results.next());

After getting the ContactCards, we could use the getFields() or getField() method to get ItemField or AggregrateField:

Listing 9. Retrieving data


AggregateField name = (AggregateField)contact.getField("N");
 if(name !=  null)
  {
   name.getField(ContactDatabase.FAMILY_NAME).getString(); //  Index 0
   name.getField(ContactDatabase.GIVEN_NAME).getString();  // Index 1
  }

With this information under our belts, we now have sufficient knowledge to build and run our sample application.

Sample application: code analysis
Download the sample.zip file from Resources below. This file contains the javaphonebook directory; extract it to your C: directory. The javaphonebook directory contains the JavaPhoneBook.java application. This application represents a phone book, which stores contact information using the Java Phone APIs we discussed in the previous section.

Let's analyze the code in JavaPhoneBook.java in some detail, starting with line 40.

Listing 10. Setting up a keyboard listener


public class JavaPhoneBook extends CFrame implements CBAListener

Because Nokia 9200 Series communicators do not, by default, have a pointer, the user interacts with applications via the keyboard, also known as the Command Button Array (CBA). Hence the JavaPhoneBook extends CFrame with implements CBAListener so that user interaction takes place through CBActionEvents. The CBA responds to CBActionEvents and hence the CFrame (which extends the Frame class) implements a CBAListener interface, which in turn extends the EventListener interface.

Lines 43 to 47 define the TextFields for user inputs firstname, lastname, workph, address, and homeph.

Listing 11. Defining TextFields for user input

 
private TextField firstName = new TextField(12) // and so on;

Lines 49 to 52 define the Menu and MenuItem for the add, find, and clear actions, which can be accessed from drop-down menus when the application is deployed and run. (You'll see how this works in the next section.)

Listing 12. Defining drop-down menu


49   private Menu editMenu=new Menu("Main  Menu");
private MenuItem createItem=new MenuItem("Add Information",new MenuShortcut(KeyEvent.VK_N));
private MenuItem findItem=new MenuItem("Find Information", new MenuShortcut(KeyEvent.VK_F));
private MenuItem clearItem=new MenuItem("Clear Fields", new MenuShortcut(KeyEvent.VK_C));

Line 54 creates an instance of the CBAHandler; lines 56 to 58 create a new CBA for add, find, and close operations.

Listing 13. Creating a new CBA


static final int ADD = EikCommandButtonGroup.BUTTON1;
static final int FIND =  EikCommandButtonGroup.BUTTON2;
static final int CLOSE = EikCommandButtonGroup.BUTTON4;

In lines 60 to 62, we declare variables for accessing the ContactDatabase, ContactCard, and Iterator to iterate over ContactCards.

Listing 14. Declaring variables


private ContactDatabase addressbook; // The contact database
private Iterator results; // Used to iterate through the search results.
private ContactCard  currentContact; // The currently active ContactCard

Lines 71 to 90 build the UI part of the application. Lines 98 to 107 create ActionListeners for menu events and handlers to catch CBA events.

Listing 15. Building a UI


editMenu.add(createItem);
 editMenu.add(findItem);
 editMenu.add(clearItem);
 menuBar.add(editMenu);
 createItem.addActionListener(this);
 findItem.addActionListener(this);
 clearItem.addActionListener(this);
 // Add the CBA Handler Events
 cba = new CBAHandler(this);
 cba.setText(ADD, "Add \n Information");
 cba.setText(FIND, "Find \n Information");
 cba.setText(CLOSE, "Close");
 cba.activate();

Line 113 calls the openDataBase() function that opens the contact address database.

Listing 16. Opening the contact address database


addressbook = ContactDatabase.openDatabase()

Lines 126 to 146 react to user actions, calling the add, find, and close functions, as appropriate. If the action is add, for instance, the createRecord() function is executed. This function creates an AggregateField (as discussed earlier) to store user-entered names and addresses, and an ItemField to store work and home phone numbers in the form of name-value pairs.

Listing 17. Calling user-requested functions


//Name in this order: Family name, given name 
 AggregateField name = new AggregateField(ContactDatabase.N);
 name.addField(new ItemField(ContactDatabase.N, lastName.getText())); // Family name
 name.addField(new ItemField(ContactDatabase.N, firstName.getText())); // Given name
//Work telephone number
 ItemField  workTel = new ItemField(ContactDatabase.TEL,  workph.getText());
 workTel.addParameter(new Parameter(ContactDatabase.TYPE, ContactDatabase.WORK));
//Home telephone number
 ItemField homeTel = new ItemField(ContactDatabase.TEL, homeph.getText());
 homeTel.addParameter(new Parameter(ContactDatabase.TYPE, ContactDatabase.HOME));
//Organization : for storing address
 AggregateField org = new AggregateField(ContactDatabase.ORG);
 org.addField(new ItemField(ContactDatabase.ORG, address.getText()));

Next, lines 215 to 233 create a ContactCard, as shown in Listing 17 below, to store the fields we created above. We then add that ContactCard to the contact database. Thus, our ContactCard holds the AggregrateField and ItemFields.

Listing 18. Creating a ContactCard


 ContactCard contact = new ContactCard();
  contact.addField(name);
  contact.addField(workTel);
  contact.addField(homeTel);
  contact.addField(org);
  // Add the ContactCard record and ensure we can  also update or delete it
  currentContact = (ContactCard)addressbook.addItem(contact);

In this way, a record (in the form of a ContactCard) is inserted into the ContactDatabase.

When we do a find operation, we search based on the lastName field. Thus, when the user clicks on the Find Information button, the displayRecord() routine is executed. Basically, we use the items() method of the ContactDatabase as discussed earlier to get the ContactCard with a lastName field that matches the text entered by the user. The logic starts on line 175:

Listing 19. Beginning of find operation logic


Iterator results = addressbook.items(ContactDatabase.N, lastName.getText());

Lines 247 to 289 get the ContactCard and retrieve the values associated with it. First we use the getField("N") method of the ContactCard APIs to retrieve the AggregateField consisting of names; then we retrieve the values of the first and last name from the AggregateField object. We follow the same procedure for the remaining fields and display their values in the appropriate fields in our user interface.

Listing 20. Find operation, continued


  ContactCard contact = (ContactCard)(results.next());
  currentContact = contact;
  // Get the name Aggregate field and split it apart to retrieve last and first name
  AggregateField name = (AggregateField)contact.getField("N");
  if(name != null)
  {
   lastName.setText(name.getField(ContactDatabase.FAMILY_NAME).getString());
   firstName.setText(name.getField(ContactDatabase.GIVEN_NAME).getString());
  }

Now that we've taken a look at the high points of our application's code, let's see how to build it so you can experiment with it on your own.

Building the application
Run the buildPhone.bat file that compiles the JavaPhoneBook.java file and creates JavaPhoneBook.jar in that same directory. buildPhone.bat assumes that the %epocroot% variable has been set; this generally happens during installation of the Symbian Nokia SDK. %epocroot% points to C:\Symbian\6.0\NokiaJava\erj, where C:\Symbian\ is the directory where you have installed the SDK.

Next, we shall create the classes that need to be deployed to the Symbian Environment on the Nokia emulator. Version 6.0 of the Symbian platform is delivered as two complete communicator reference designs (aka DRFDs): Quartz, for pocket-sized, palmtop devices, and Crystal, for powerful, keyboard-based, wireless information devices. Each device family has a shell program -- Extras on Crystal, and the Launcher on Quartz -- that allows the user to run application programs. Quartz is a tablet communicator with convenient pocket-sized, palmtop form factor.

To run an application from either shell program, you need at least the following two files:

  • An EPOC application file (.app), which, at minimum, contains a unique identifier (UID) to identify the program.
  • An application information file (.aif) to specify the icon and caption that will represent the phone on a menu screen.

Other files might also be required, depending on the programming language of the application. For example, a Java program needs an additional text file (.txt) to specify the correct command line to the JVM when the application is launched.

AIF Builder is an application that runs on your development machine (not the device or the emulator) to help you easily create the required files. It works with several device families and programming languages.

Open the AIF Tool Builder from Program Files -> Symbian 6.0SDK -> Development Tools. Select New from the File menu, and select Java as the application language in the Application Details pane, as shown in Figure 1.

Figure 1. AIF Builder Application Details pane
AIF Builder Application Details pane

Type in JavaPhoneBook in the Application Name field. For Application UID, type in 0x01000000, which uniquely identifies the application. Each application must have its own UID. A UID is a 32-bit number, which you can get as you need from Symbian (see Resources). During development, you can choose temporary UIDs within the range from 0x01000000 to 0x0fffffff. Care must still be taken to ensure that no two programs have the same UID; such a conflict could stop a program from loading correctly, typically leading to NotFound errors.

Finally, type in the following as the Java Command Line Text field value:


-cp JavaPhoneBook.jar -Dcom.symbian.appName="JavaPhoneBook" navexamples.JavaPhoneBook 

This tells the JVM on the emulator or device to run the appropriate class file for the JavaPhoneBook application.

Next, select the DRFD's pane (see Figure 2) to select the device family or families for which the application is written. In the DRFD's To Generate For option list, check only the box next to Crystal, as we are developing for Crystal-based devices. In the Location to Generate Files field, select the directory where you have the JavaPhoneBook.jar file and the files extracted from sample.zip; you can use any existing folder as the output directory for temporary files.

Figure 2. AIF Builder DRFDs pane
AIF Builder DRFDs pane

Click on the Generate button and four files will be created: JavaPhoneBok.aif, JavaPhoneBok.app, JavaPhoneBok.txt, and a temporary file named JavaPhoneBook.rss.

Running the application
We'll need to move the JavaPhoneBook folder to the applications directory where the emulator or device can find it. Copy the directory to C:\Symbian\6.0\NokiaJava\Epoc32\Wins\c\System\Apps. Note that you only need the three files we generated at the end of the last section (excluding the temporary file) plus the JavaPhoneBook.jar, so the remaining files in the JavaPhoneBook directory can be deleted. When you run the emulator, the application JavaPhoneBook will now appear in the Extras section of the emulator menu as shown in Figure 3 below. (To run the emulator, select Program Files- > Symbian 6.0 SDKS -> Nokia Java -> Emulator(rel).)

Figure 3. Emulator Extras menu
Emulators Extras menu

Click on Open and the screen in Figure 4 appears. Enter the information requested and select Add Information, which is nothing but a CBA button that fires the appropriate createRecord() method. The information is added to the ContactDatabase.

Figure 4. Adding an address to the database
Adding an address to the database

You could also add information from the menu section. Press the F1 key on your keyboard to access the drop-down menus. Select Main Menu -> Add Information as shown in Figure 5. This menu event corresponds to the menu events that we have programmed.

Figure 5. Using a drop-down menu
Using a drop-down menu

Select Clear Fields from the Main Menu to clear all the information. Then type in the last name of the person for whom you want to search and click Find Information as shown in Figure 6.

Figure 6. Searching the database
Searching the database

You should see the data being populated in the remaining fields if the last name is found in the ContactDatabase, as shown in Figure 7.

Figure 7. Search results
Search results

Thus, we have successfully built our phone book application.

Deploying the application on an actual device
To deploy our application to a real Symbian OS device, we must create a Symbian installation (SIS) for it. The SDK includes the necessary tool for this, an executable named makesis.exe. This tool needs a .pkg (package) file as input that contains the application information and files that need to be deployed. Refer to the Symbian developers' Web site (see Resources) to learn how to create an SIS file for any application.

Conclusion
We've now built a sample Java-based application on the Symbian platform and deployed and tested it on our Nokia emulator. This application build can be transferred on to our actual Nokia 9200 series devices. You should now be able to use your existing Java background and your new knowledge of the Java Phone APIs to start developing applications for this useful class of devices. Now you need to put your creativity to work and think about what kind of apps Symbian users need!

Resources

  • To work with the examples on your desktop machine, you need to download the Nokia 9200 Communicator Series SDK for Symbian OS from Nokia's Web site.

  • Download sample.zip, which contains the full code of this article's sample application.

  • Download download.zip, which contains a batch file, cascading style sheet, and MS DOS code.

  • Sun's PersonalJava FAQ explains how PersonalJava fits in with the J2ME platform.

  • For more on J2ME and how PersonalJava will fit into its structure, see "J2ME grows up," by Todd Sundsted (developerWorks, May 2001).

  • Learn more about the vCard protocol.

  • Once you've completed your Symbian-based application, you'll need to go to the Symbian Web site to get a unique UID for it. This site also has more information on creating SIS files with which you can deploy your application to a real device.

  • Check out the latest initiatives at IBM's pervasive computing site.

  • Build Java apps with VisualAge for Java.

About the author
Naveen Balani works as a technical analyst for Syntel India, Ltd. His job profile includes designing, developing, and implementing J2EE-based products. You can reach Naveen at naveenbalani@rediffmail.com.


code1,952 KBe-mail it!

What do you think of this document?
Killer! (5) Good stuff (4) So-so; not bad (3) Needs work (2) Lame! (1)

Comments?



developerWorks > Wireless | Java technology
developerWorks
  About IBM  |  Privacy  |  Terms of use  |  Contact