Archive for November, 2006|Monthly archive page

Bluetooth Checkers!!!

My bluetooth checkers game is ready to go!!!

If your MIDP 2 handset supports JSR 82 (Bluetooth API), you can download and install it (free) from my usual checkers wml page or my games html page!!!

I promise this is the last Checkers version (for a long time anyway 😉 ), and next I’ll move on to some graphics discussions. But I wanted to take one standard game and program it using a few different protocols to compare and contrast how each one works in a multiplayer game.

I think Bluetooth is a little more challenging and complicated to program than SMS. Part of the reason for that is that SMS uses the operators’ standard way of routing communications to a handset. You find the right destination by typing in the right phone number. And it’s the same phone number you’d use to route other comunications to that device. So you don’t have to reinvent the wheel to find, identify, and authenticate the device you’re looking for.

Bluetooth allows you to find all active, bluetooth-enabled devices within range and see what kind of services they offer. Each server offering a bluetooth service publishes a set of detailed service records describing the services available. So you have a fair amount of work on the server side creating useful descriptions and on the client side reading the descriptions and choosing the right service on the right device. Add to that the fact that you have the option of choosing a plain socket type connection or discrete packets, different authentication and/or encryption schemes, and even object-oriented communications using Java OBEX, you have practically unlimited potential to customize (and complicate 😉 ) your application according to your needs.

In my case, I decided I wanted to make my game’s communications as simple as possible. So I started with the assumption — since bluetooth is a protocol for local communications — that you and your friend are in the same room together and have verbally agreed to start up a game of checkers on your two handsets. My checkers game is fundamentally a peer-to-peer type game, but bluetooth is a client-server protocol, so I had my game start with a screen where the user can choose whether his handset will be acting as the client or as the server (the first player selects server and the second client).

Then there was the question of writing the code so that the two devices will find each other instead of finding other random bluetooth devices and services. Fortunately — with a simple services like this one — all you really need is a UUID. You can create your own UUID (in both Linux and Windows) using the uuidgen command. Then on the server side, all you need to do is construct your bluetooth URL using your UUID and open the connection and wait for clients to call you up. My game’s server URL looks like this:

btspp://localhost:2BBC2D287C8C11DBA1500040F45842EF;name=Checkers;authorize=false

The “btspp” indicates that I’d like to use the bluetooth streaming (socket-like) protocol, the “localhost” makes me a server; then I add on my UUID (what the “uuidgen -t” with the hyphens removed), then some attributes (the application name and the fact that I don’t want to require authorization). Opening this connection creates the corresponding service record, which you can get a handle to and add attributes to if you like. The WTK’s BluetoothDemo shows a good example of how to add additional descriptive attributes. The BluetoothDemo has a server that makes images available for bluetooth clients to download, and there you can see the programmer has added a custom attribute to give the name of the image being offered. As you can see in the ServiceRecord JavaDoc, there are a number of common standard attributes that you can use as well. The attributes aren’t too complicated to use — you just need to keep in mind that different attributes values can be of different types so the values are wrapped in DataElements that allow you to handle all of the different types of values in a consistent way.

Once your server is up and running, the next thing is to program the client to find it and connect to it. Basically, all you need to do is grab a handle to the local DiscoveryAgent and send it off in search of devices and services. It toodles around on its own thread looking for them, then it calls the assigned DiscoveryListener when it’s done.

Discovery is a two-step procedure: First you gather a list of devices, then you search the devices for the service you want. (Since I didn’t bother with any special service record attributes on the server side, when I started searching my device list for services I sent a null attrSet to the searchServices method.) Note that if you’re writing a program where the client frequently reconnects to the same set of known servers, you can optimize discovery by caching a list of known devices.

It might seem like you could simplify the discovery procedure by calling the method DiscoveryAgent.selectService() which finds all of the available connections that provide the desired service (without first getting all the devices and searching each one). Or that you could optimize by searching each device for services as you find it rather than first finding all devices and then searching them one by one. However, over on developer.sun.com I found this interesting little powerpoint presentation full of bluetooth programming best practices, and this little slideshow specifically says not to do either one of those things. Because they seem like good ideas, but really the lead to nothing but badness. And I figure that if anyone would know the people over at developer.sun.com would, so I decided to follow their advice.

Once the client side of the program and the server side find each other, the rest is a breeze! Whew! From then on it’s just standard Java socket programming. The server’s acceptAndOpen command stops blocking and returns a handle to the connection. Both the client and the server open the InputStream and OutputStream of their respective connections, and start sending each other data. All you have to do is send the right data down the stream and read it and interpret it correctly on the other side. What could be easier? 😉

For the bluetooth version of the checkers game, I eliminated the “taunt” feature I’d added for SMS Checkers. With SMS checkers, you can play against your friend wherever he may be. When you start up the game and enter your friend’s phone number — thanks to the push registry — the invitation SMS will buzz his handset to invite him to play whether he’s on the other side of the world or in a meeting or whatever. So it’s useful to be able to send a text message along with every move. In the bluetooth version you essentially have to have already agreed together that you want to play, so the taunt feature is less useful. It would have been possible to hook up the bluetooth version to the push registry as well, but I figured it was already complicated enough as it is.

So please try it out and tell me what you think!

More about JSR 75

For today’s JSR adventure, I improved my SMS checkers game — as promised — by adding a feature to read contacts from the handset address book to choose opponents. The new version is available as CheckersPlus. Then I figured that since I’m playing with JSR 75, I should write a sample program to test the other half of JSR 75: the FileConnection API.

I like the elegance of the FileConnection API, and in particular the way it’s designed to function just like the various network connection APIs (using Connector.open with a URL, returning a Connection with an InputStream and and OutputStream just as any a network connection). It’s a very natural way of accessing files both from the Java perspective (where files have traditionally been accessed through the same streams as sockets, etc.) and in the general networking universe (where users are already accustomed to reading local files in an Internet browser using a file://-type url).

Another cool advantage to FileConnection is that you can access parts of the handset’s memory that you can’t touch from MIDP’s standard little RMS memory sandbox. I found by listing the available file roots on my Sagem my700x that I can access the images folder. So for some handsets it may be possible to have a Java MIDlet store a wallpaper or a ringtone as a wallpaper or a ringtone by storing it in the right place where the handset can use it.

But that brings us to the usual disadvantage: you have to know the particular handset very well to know which folders you have access to and how to access them. So it’s great if your project has a small set of target handsets, and not so great if you want your application to be useful on all MIDP handsets across the board. The RMS (Record Management System) has the advantage of always being supported, so it’s probably better to use the RMS if all you want is to set some simple data aside and find it again later.

Of course, even the RMS isn’t as predictible as one might like. There are handsets where RMS access is slower than FileConnection access (and some where it’s not), some that handle individual records in unexpected ways (setting aside a big space for each record even if it’s not used, or failing to free up the memory of a deleted record). Then there’s the fact that the RMS is not convenient for pooling data among multiple MIDlet suites: To share a record store between suites, you need to leave the access door open to every MIDlet on the device, plus the record store is deleted when the associated MIDlet suite is deleted even if other MIDlet suites still wanted to access the data.

So, there’s a bit of a trade-off, meaning it’s better to know both the FileConnection API as well as the RMS, and choose which one to use depending on your application.

For today’s fun, here’s a sample class to illustrate the FileConnection API, doing a few very basic, standard things like listing the available roots and files; reading, writing, creating a test file, etc. As with PIM, FileConnection access is done in its own thread:

package net.frog_parrot.test;

import java.util.Enumeration;
import java.io.*;

import javax.microedition.io.*;
import javax.microedition.io.file.*;

/**
* A simple file Connection testing utility.
*/
public class FCRunner extends Thread {

FCTest myMidlet;

FCRunner(FCTest test) {
myMidlet = test;
}

public void run() {
FileConnection rootdir = null;
try {
Enumeration items = FileSystemRegistry.listRoots();

// Now print the available roots:
while(items.hasMoreElements()) {
String rootname = (String)(items.nextElement());
myMidlet.display(“\n *** new root: ” + rootname);

// open the root directory:
// note there are three slashes before the root name
// because there is no “host” for this connection:
rootdir = (FileConnection)Connector.open(
“file:///” + rootname);
// List the current files:
Enumeration ls = rootdir.list();
while(ls.hasMoreElements()) {
String filename = (String)(ls.nextElement());
myMidlet.display(” file: ” + filename);

// print the contents of the file:
FileConnection file = null;
try {
file = (FileConnection)Connector.open(
“file:///” + rootname + “/” + filename);
if(file.canRead()) {
InputStream is = file.openInputStream();
byte[] contents = new byte[25];
int len = is.read(contents);
is.close();
myMidlet.display(” contents: ”
+ new String(contents, 0, len));
} else {
myMidlet.display(” * not readable”);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
file.close();
} catch(Exception e) {}
}
}

// now try to create a file:
FileConnection newfile = null;
try {
newfile = (FileConnection)Connector.open(
“file:///” + rootname + “myNewFile”);
if(newfile.exists()) {
OutputStream os = newfile.openOutputStream();
os.write((new String(“overwriting old contents”)).getBytes());
os.close();
} else {
newfile.create();
OutputStream os = newfile.openOutputStream();
os.write((new String(“creating new contents”)).getBytes());
os.close();
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
newfile.close();
} catch(Exception e) {}
}
}
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
rootdir.close();
} catch(Exception e) {}
}
}

}

For completeness, here’s the MIDlet class to use to run the above FileConnection-testing class.  These two classes together make a complete MIDlet that can be easily built by creating a new project for it in the WTK:

package net.frog_parrot.test;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;

/**
* A simple MIDlet to test which APIs are implemented.
*/
public class FCTest extends MIDlet implements CommandListener {

private Command myExitCommand = new Command(“Exit”, Command.EXIT, 1);
private Command myOkCommand = new Command(“OK”, Command.OK, 1);
private Form myResultScreen;

/**
* Empty constructor.
*/
public FCTest() {
}

/**
* Initialize the Displayables.
*/
public void startApp() {
myResultScreen = new Form(“Results”);
myResultScreen.addCommand(myExitCommand);
myResultScreen.addCommand(myOkCommand);
myResultScreen.setCommandListener(this);
Display.getDisplay(this).setCurrent(myResultScreen);
}

/**
* Implementation of MIDlet.
*/
public void pauseApp() {
}

/**
* Implementation of MIDlet.
*/
public void destroyApp(boolean unconditional) {
}

/**
* Respond to a button push.
*/
public void commandAction(Command command, Displayable screen) {
if(command == myExitCommand) {
destroyApp(true);
notifyDestroyed();
} else {
FCRunner runner = new FCRunner(this);
runner.start();
}
}

/**
* Append a string to the current display.
*/
public void display(String str) {
myResultScreen.append(str);
myResultScreen.append(“\n”);
}

}

A simple PIM example

Now that I’ve got my SMS Checkers game up and running, I’d like to play it against a friend. But I don’t want to have to type my friend’s mobile number into that little phone number text field every time — really I don’t even know his number off the top of my head since I always just call people by selecting numbers from my address book. What to do?

This looks like a job for JSR 75: PIM!!!

JSR 75 also covers the File Connection API, but for today let’s talk about the Personal Information Management API.

Browsing through the JavaDoc, it seems pretty clear that this API is one where they’ve opted for flexibility over simplicity. The addressbooks, calendars, and to-do lists on the various handsets each have a fixed structure, however there’s no reason to expect all of these personal information datastores to have the same structure as each other. So the PIM API was designed to allow you to find the fields and records you need regardless of the underlying structrure of the datastore.

It’s actually a little confusing to try to figure out from the JavaDoc how to get the information you want. Fortunately, there aren’t too many classes. The classes to focus on are PIMItem and PIMList, which essentially describe records and record stores respectively. Between these two classes (and subclasses such as Contact), you’ll find the methods you need to determine what fields (such as TEL) a record has data for, which attributes (such as HOME or MOBILE) are associated with the field, and what type of data the (such as String or int) is contained in the field.

Confused yet?

My first instinct in such a case is to just write a simple example program.

It took a few tries, so I was a little disappointed that there was no clear() method to delete the whole ContactList so I could start over. Yet, it’s probably wise of the API designers to have left that off considering that in real life if your program deletes the user’s entire address book — even if he gave permission to modify it — this would lead to a “bad user experience” in every case. So it’s better not to even have the method there to tempt you to deliberately write some malicious code, which is a no-no in Java ;-).

The solution I found (for the WTK) is just to delete all the files in the following directory whenever I wanted to start over with a clean slate: WTK2.2/appdb/DefaultColorPhone/pim/contacts/Contacts/

The following class creates a couple of very simple records then iterates through the resulting record store printing out exactly what kind of data structure was created. Note that this example isn’t something you’d put in a real application (especially given all the System.out.println() statements). Also note that I made it a subclass of Thread. Accessing the PIM system is a potentially blocking operation that should not be done from any method that needs to return immediately such as startApp() or commandAction().

Here’s the code:

package net.frog_parrot.test;

import java.util.Enumeration;

import javax.microedition.pim.*;

/**
* A simple PIM testing utility.
*/
public class PIMRunner extends Thread {

  public void run() {
      try {
        ContactList addressbook
            = (ContactList)(PIM.getInstance().openPIMList(
            PIM.CONTACT_LIST, PIM.READ_WRITE));
        Contact contact = null;

        // Each PIMItem -- new or found -- is associated with
        // a particular PIMList.
        contact = addressbook.createContact();
        if(addressbook.isSupportedField(Contact.FORMATTED_NAME)) {
          contact.addString(Contact.FORMATTED_NAME, Contact.ATTR_NONE,
             "Lynn Hanson");
        }
        if(addressbook.isSupportedField(Contact.TEL)) {
          contact.addString(Contact.TEL, Contact.ATTR_HOME,
             "555-HOME-NUMBER");
          contact.addString(Contact.TEL, Contact.ATTR_MOBILE,
                            "555-MOBILE-NUMBER");
        }
        // Here's a quick search to see if this contact
        // is already present in the addressbook:
        Enumeration matching = addressbook.items(contact);
        if(matching.hasMoreElements()) {
          System.out.println("found the first contact");
        } else {
          System.out.println("adding the first contact");
          contact.commit();
        }
      
        // Let's create one more contact:
        contact = addressbook.createContact();
        if(addressbook.isSupportedField(Contact.FORMATTED_NAME)) {
          contact.addString(Contact.FORMATTED_NAME, Contact.ATTR_NONE,
             "Spencer Hobbs");
        }
        if(addressbook.isSupportedField(Contact.TEL)) {
          contact.addString(Contact.TEL, Contact.ATTR_HOME,
             "5555-HOME-NUMBER");
          contact.addString(Contact.TEL, Contact.ATTR_MOBILE,
             "5555-MOBILE-NUMBER");
        }
        matching = addressbook.items(contact);
        if(matching.hasMoreElements()) {
          System.out.println("found the second contact");
        } else {
          System.out.println("adding the second contact");
          contact.commit();
        }
            
        // Now print the contents of the addressbook:
        Enumeration items = addressbook.items();
        while(items.hasMoreElements()) {
          System.out.println("\n *** new item ***");
          contact = (Contact)(items.nextElement());
          int[] fields = contact.getFields();
          for(int i = 0; i < fields.length; i++) {
            int fieldIndex = fields[i];
            System.out.println(" field " + fieldIndex + ": "
                + addressbook.getFieldLabel(fieldIndex));
            int dataType = addressbook.getFieldDataType(fieldIndex);
            System.out.println(" * data type: " + dataType);
            if(dataType == PIMItem.STRING) {
              for(int j = 0; j < contact.countValues(fieldIndex); j++) {
                int attr = contact.getAttributes(fieldIndex, j);
                System.out.print(" " + j + ". (");
                System.out.print(addressbook.getAttributeLabel(attr) + "): ");
                System.out.println(contact.getString(fieldIndex, j));
              }
            }
          }
        }
      } catch(Exception e) {
        e.printStackTrace();
      }
  }
  
}

And here’s what it printed out:

adding the first contact
adding the second contact

*** new item ***
field 105: Formatted Name
* data type: 4
0. (None): Lynn Hanson
field 114: Revision
* data type: 2
field 115: Tel.
* data type: 4
0. (Home): 555-HOME-NUMBER
1. (Mobile): 555-MOBILE-NUMBER
field 117: UID
* data type: 4
0. (None): 1.vcf

*** new item ***
field 105: Formatted Name
* data type: 4
0. (None): Spencer Hobbs
field 114: Revision
* data type: 2
field 115: Tel.
* data type: 4
0. (Home): 5555-HOME-NUMBER
1. (Mobile): 5555-MOBILE-NUMBER
field 117: UID
* data type: 4
0. (None): 2.vcf

Fun with mobile blogging!!!

I just noticed this past weekend that I can read this blog from my handset!!!

mobile java blog

The cool thing is that if you’re reading this on your handset right now, you can click on this link to my games page and from there download the sample games and programs right onto your handset and try them out!!!

I’ve made a new HTML version of my games page (the above link) since my current handset is capable of reading and displaying html. For those whose handsets support only WML (not HTML), I have two WML pages available that link to the same sample programs: http://frog-parrot.net/hello.wml and http://frog-parrot.net/checkers.wml. Please feel free to link to any of these pages.

Even though I’m now mobile-blogging 😉 , it somehow feels like I’m not getting the complete mobile blogging experience since I’m only reading the blog from my handset (posting from my hopelessly non-mobile PC…)

I could probably remedy this by using some tips from this introduction to mobile blogging article by

I’m a little skeptical of this idea since the most interesting photo blogs tend to be written by serious photo hobbyists (if not professional photographers) who have real cameras. And in my own case, I’ve mostly been posting photos of my handset, which are tricky to take using the handset’s built in camera… But who knows? Maybe this idea will become popular.

Actually I’m tempted to combine this “mobile photo blog” idea with the following handset bug I read about recently:

Q: My Nokia 6131 keep taking photos whilst in my pocket – Why?

A: Unfortunately the camera button is on the side of the handset and there is no lock for this. this cannot be changed.

Lots of handsets have strange bugs, so I don’t know why I find this one so hilarious. “My handset keeps taking pictures of the inside of my pocket!” “Um… There’s nothing we can do about that, sorry.” lol

I think this would make a great experimental / performance art blog: “photosMyHandsetSpontaneouslyTookOfTheInsideOfMyPocket.wordpress.com”

Don’t any of you steal this idea before I get around to doing it. 😉

SMS Checkers!!!

My SMS checkers game is done and now available!!! Try it out!!!

Just go here to download it free onto any MIDP 2 phone:

http://www.frog-parrot.net/checkers.wml

This version is a big improvement on the original. First of all, it’s a peer-to-peer game — relying entirely on exchanging SMS messages from one handset to the other — so any two people who both have the game installed can play it without worrying about whether a central server is up and running and accessible. The server wasn’t doing much more than routing the game moves from one handset to the other, so it was fairly easy to write it out of the picture.

Each move requires sending a whole SMS, yet the move data typically takes no more than five bytes. It seemed like such a shame to waste the rest of the SMS payload, so I added a “taunt” feature so that you can send your opponent a message along with your move if you like!!!

Another new feature is that the game can now recover from a pause — so you can receive a call and then return to the checkers game in progress.

Additionally I did a bunch of refactoring. The original game logic was great, but the meta-logic — the game state, whose turn it is, etc. — was too intimately tied to the communications/networking code. That makes for smaller code, but the game is already pretty small (16K). So I modularized it a bit, making separate classes for the game state logic and the communications code. Ah, with a personal project you get the luxury of taking the time to refactor the code when there’s a change in requirements! 😉

If you try this game, please feel free to post any comments about it, suggested improvements, etc. Thanks.