Hi,

I've written a small MIDlet to try and highlight a potential bug in the Nokia development suite. I'm using the Series 60 Emulator 0.3 Beta to run this MIDlet.

What *should* happen is that you are able to click start and stop alternately as many times as you want. The problem is that once you've clicked start and stop, the user interface hangs. Something is going wrong with the user interface thread. If I don't use the service variable (i.e. if the PlayerGameThread is modified so that it doesn't try and open a connection) then the thread dies as expected and there's no problem with the user interface.

I've been working on this for a fair while. Ideas anyone?


<code>
import java.io.IOException;

import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnectionNotifier;
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;
import javax.microedition.midlet.MIDletStateChangeException;


/**
* By opening up a bluetooth service, something very wrong happens
* when you try to close everything.
*/
public class BluetoothServiceExample extends MIDlet implements CommandListener {

private Form main = new Form("Example");
private Command startCommand = new Command("Start", Command.OK, 1);
private Command stopCommand = new Command("Stop", Command.OK, 1);

protected void startApp() throws MIDletStateChangeException {
main.addCommand(startCommand);
main.setCommandListener(this);
main.append("Stopped");
Display.getDisplay(this).setCurrent(main);
}


protected void pauseApp() {
}


protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}


public void commandAction(Command c, Displayable d) {
System.out.println("commandAction called: " + c);
if(c == startCommand) {
System.out.println("Changing menu");
main.deleteAll();
main.append("Started");
main.removeCommand(startCommand);
main.addCommand(stopCommand);
System.out.println("Finished changing menu");
PlayerGameThread.getInstance().startGame();
}
else if(c == stopCommand){
System.out.println("Changing menu");
main.deleteAll();
main.append("Stopped");
main.removeCommand(stopCommand);
main.addCommand(startCommand);
System.out.println("Finished changing menu");
PlayerGameThread.getInstance().stopGame();
}
System.out.println("commandAction finished");
}
}


class PlayerGameThread implements Runnable {
public static final UUID JOIN_GAME_UUID = new UUID("01020304050607080910111213141516", false);

private boolean running = false;
private Thread runningThread = null;

private StreamConnectionNotifier service;

//Singleton pattern
private static PlayerGameThread instance;
private PlayerGameThread() {}
public static synchronized PlayerGameThread getInstance() {
if(instance == null) {
instance = new PlayerGameThread();
}
return instance;
}


public synchronized void startGame() {
if(!running) {
System.out.println("Game Starting");
running = true;
runningThread = new Thread(this);
runningThread.start();
System.out.println("Game Started");
}
else {
System.out.println("startGame() called when game is running");
}
}


public synchronized void stopGame() {
if(running) {
System.out.println("Game Stopping");
running = false;

//We have to kill the service in case we've called
//acceptAndOpen() and the thread is blocking
if(service != null) {
try {
service.close();
}
catch(IOException ex) {
ex.printStackTrace();
}
service = null;
}

System.out.println("Waiting until the PlayerGameThread has finished");
try {
runningThread.join();
}
catch(InterruptedException ex) {
ex.printStackTrace();
}

runningThread = null;
System.out.println("Game Stopped");
}
else {
System.out.println("stopGame() called when game is not running");
}
}


/**
* This method should not be called directly by the developer.
*/
public void run() {
try {
service = (StreamConnectionNotifier)Connector.open("btspp://localhost:" + JOIN_GAME_UUID);
}
catch(IOException ex) {
ex.printStackTrace();
}

while(running) {
System.out.println("Listening for a connection");
try {
service.acceptAndOpen();
}
catch(IOException ex) {
ex.printStackTrace();
}
System.out.println("Incoming connection");
}//end while(running)

System.out.println("PlayerGameThread finished");
}
}
</code>

Many thanks,
Dave