|
The J2ME Mobile Information Device Profile
Using the State Pattern |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
MIDlets that are the
CommandListener for multiple
Displayable objects
if statement
package gui;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* An abstract "screen" in a MIDlet
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public abstract class AbstractScreen
{
protected ApplicationContext context;
public static final String CANCEL = new String("Cancel");
public static final String EXIT = new String("Exit");
public static final String INFORMATION = new String("Information");
public static final String OK = new String("OK");
public static final String SELECT = new String("Select");
protected static final Command CANCEL_COMMAND = new Command(CANCEL, Command.CANCEL, 1);
protected static final Command EXIT_COMMAND = new Command(EXIT, Command.EXIT, 1);
protected static final Command OK_COMMAND = new Command(OK, Command.OK, 1);
protected static final Command SELECT_COMMAND = new Command(SELECT, Command.SCREEN, 1);
/**
* Explicit Value Constructor
*
* @param context The application context
*/
public AbstractScreen(ApplicationContext context)
{
this.context = context;
}
/**
* Enter this instance of an AbstractScreen
*/
public void enter()
{
Display display;
Displayable displayable;
context.setState(this);
displayable = getDisplayable();
displayable.setCommandListener(context);
display = context.getDisplay();
display.setCurrent(displayable);
}
/**
* Get the ApplicationContext for this "screen"
*/
protected ApplicationContext getContext()
{
return context;
}
/**
* Get the Displayable associated with this AbstractScreen
*
* @returns The Displayable
*/
protected abstract Displayable getDisplayable();
}
package gui;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* The context (in the sense of the StatePattern) for a MIDlet
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public interface ApplicationContext extends CommandListener
{
/**
* Get the Display associated with this ApplicationContext
*
* @return The Display
*/
public abstract Display getDisplay();
/**
* Set the current state for this ApplicationContext
*
* @param state The new AbstractState
*/
public abstract void setState(AbstractScreen state);
}
MIDlet
package phoneycall;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import gui.*;
/**
*
*/
public class PhoneyCall extends MIDlet implements ApplicationContext
{
private AbstractScreen currentScreen, previousScreen;
private AbstractState state;
private Display display;
/**
* Handle a Command
*
* @param c The Command
* @param d The Displayable that generated the Command
*/
public void commandAction(Command c, Displayable d)
{
String ac;
ac = c.getLabel();
if (ac.equals(AbstractState.CANCEL))
state.handleCancel();
if (ac.equals(AbstractState.OK))
state.handleOK();
if (ac.equals(AbstractState.SELECT))
state.handleSelect();
}
/**
* Destroy this MIDlet
*
* @param unconditional true to destroy under any circumstances
*/
public void destroyApp(boolean unconditional)
{
}
/**
* Get the Display
*
* @return The Display
*/
public Display getDisplay()
{
return display;
}
/**
* Pause this MIDlet
*/
public void pauseApp()
{
}
/**
* Set the current state for this ApplicationContext
*
* @param state The new AbstractState
*/
public void setState(AbstractScreen state)
{
this.state = (AbstractState)state;
}
/**
* Start this MIDlet
*/
public void startApp()
{
display = Display.getDisplay(this);
state = CallCountScreen.enter(this);
}
}
AbstractState for this Examplepackage phoneycall;
import javax.microedition.lcdui.*;
import gui.*;
/**
*/
public abstract class AbstractState extends AbstractScreen
{
/**
* Explicit Value Constructor
*/
public AbstractState(ApplicationContext context)
{
super(context);
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
return null;
}
/**
* Handle a CANCEL_COMMAND
*/
public void handleCancel()
{}
/**
* Handle an OK_COMMAND
*/
public void handleOK()
{}
/**
* Handle a SELECT_COMMAND
*/
public void handleSelect()
{}
}
package phoneycall;
import javax.microedition.lcdui.*;
import gui.*;
/**
* The CallCountScreen in PhoneyCall
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CallCountScreen extends AbstractState
{
private List list;
private static CallCountScreen instance;
private static final String MULTIPLE = new String("Multiple Calls");
private static final String ONE = new String("One Call");
/**
* Explicit Value Constructor
*/
private CallCountScreen(ApplicationContext context)
{
super(context);
list = new List("Number of Calls?", List.IMPLICIT);
list.append(ONE, null);
list.append(MULTIPLE, null);
list.setSelectCommand(SELECT_COMMAND);
}
/**
* Get the Displayable associated with this AbstractState
*
* @returns The Displayable
*/
protected Displayable getDisplayable()
{
return list;
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
if (instance == null) instance = new CallCountScreen(context);
instance.enter();
return instance;
}
/**
* Handle a SELECT_COMMAND
*/
public void handleSelect()
{
int index;
String ac;
index = list.getSelectedIndex();
ac = list.getString(index);
if (ac.equals(ONE))
SingleCallScreen.enter(context);
else if (ac.equals(MULTIPLE))
MultipleCallScreen.enter(context);
}
}
package phoneycall;
import javax.microedition.lcdui.*;
import gui.*;
/**
* The SingleCallScreen in PhoneyCall
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class SingleCallScreen extends AbstractState
{
private Form form;
private TextField delay;
private static SingleCallScreen instance;
/**
* Explicit Value Constructor
*
* @param context The ApplicationContext
*/
private SingleCallScreen(ApplicationContext context)
{
super(context);
form = new Form("Single Call Details");
delay = new TextField("Delay (sec.):", "5", 6, TextField.NUMERIC);
delay.setLayout(Item.LAYOUT_EXPAND|Item.LAYOUT_NEWLINE_AFTER);
form.append(delay);
form.addCommand(CANCEL_COMMAND);
form.addCommand(OK_COMMAND);
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
if (instance == null) instance = new SingleCallScreen(context);
instance.enter();
return instance;
}
/**
* Get the Displayable associated with this AbstractState
*
* @returns The Displayable
*/
protected Displayable getDisplayable()
{
return form;
}
/**
* Handle a CANCEL_COMMAND
*/
public void handleCancel()
{
CallCountScreen.enter(context);
}
/**
* Handle an OK_COMMAND
*/
public void handleOK()
{
CallersScreen next;
int n;
WaitingScreen waiting;
// Set the attributes of the WaitingScreen
waiting = WaitingScreen.createInstance(context);
try
{
n = Integer.parseInt(delay.getString());
}
catch (NumberFormatException nfe)
{
n = 5;
}
waiting.setDelay(n);
waiting.setNumber(1);
waiting.setInterval(n);
// Set the attributes of the CallersScreen
next = CallersScreen.createInstance(context);
next.setPreviousState(this);
// Enter the CallersScreen
next.enter();
}
}
package phoneycall;
import javax.microedition.lcdui.*;
import gui.*;
/**
* The MultipleCallScreen in PhoneyCall
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class MultipleCallScreen extends AbstractState
{
private Form form;
private TextField delay, interval, number;
private static MultipleCallScreen instance;
/**
* Explicit Value Constructor
*
* @param context The ApplicationContext
*/
private MultipleCallScreen(ApplicationContext context)
{
super(context);
form = new Form("Multiple Call Details");
number = new TextField("No. of Calls:", "6", 6, TextField.NUMERIC);
number.setLayout(Item.LAYOUT_EXPAND|Item.LAYOUT_NEWLINE_AFTER);
form.append(number);
interval = new TextField("In the next (sec.):", "120", 6, TextField.NUMERIC);
interval.setLayout(Item.LAYOUT_EXPAND|Item.LAYOUT_NEWLINE_AFTER);
form.append(interval);
delay = new TextField("First call in (sec.):", "5", 3, TextField.NUMERIC);
delay.setLayout(Item.LAYOUT_EXPAND|Item.LAYOUT_NEWLINE_AFTER);
form.append(delay);
form.addCommand(CANCEL_COMMAND);
form.addCommand(OK_COMMAND);
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
if (instance == null) instance = new MultipleCallScreen(context);
instance.enter();
return instance;
}
/**
* Get the Displayable associated with this AbstractState
*
* @returns The Displayable
*/
protected Displayable getDisplayable()
{
return form;
}
/**
* Handle a CANCEL_COMMAND
*/
public void handleCancel()
{
CallCountScreen.enter(context);
}
/**
* Handle an OK_COMMAND
*/
public void handleOK()
{
CallersScreen next;
int n;
WaitingScreen waiting;
// Set the attributes of the WaitingScreen
waiting = WaitingScreen.createInstance(context);
try
{
n = Integer.parseInt(number.getString());
}
catch (NumberFormatException nfe)
{
n = 5;
}
waiting.setNumber(n);
try
{
n = Integer.parseInt(interval.getString());
}
catch (NumberFormatException nfe)
{
n = 5;
}
waiting.setInterval(n);
try
{
n = Integer.parseInt(delay.getString());
}
catch (NumberFormatException nfe)
{
n = 5;
}
waiting.setDelay(n);
// Set the attributes of the CallersScreen
next = CallersScreen.createInstance(context);
next.setPreviousState(this);
// Enter the CallersScreen
next.enter();
}
}
package phoneycall;
import javax.microedition.lcdui.*;
import gui.*;
/**
* The CallersScreen in PhoneyCall
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class CallersScreen extends AbstractState
{
private AbstractState previousState;
private List list;
private static CallersScreen instance;
/**
* Explicit Value Constructor
*
* @param context The ApplicationContext
*/
public CallersScreen(ApplicationContext context)
{
super(context);
list = new List("Select Caller(s)", List.MULTIPLE);
list.append("Aboutabl, Mohamed", null);
list.append("Abzug, Charles", null);
list.append("Adams, Elizabeth", null);
list.append("Bernstein, David", null);
list.append("Buchholz, Florian", null);
list.append("Cushman, Pauline", null);
list.append("Daughtrey, Taz", null);
list.append("Fox, Christopher", null);
list.append("Grove, Ralph", null);
list.append("Harris, J. Archer", null);
list.append("Harris, Nancy", null);
list.append("Heydari, M. Hossain", null);
list.append("Lane, Malcolm", null);
list.append("Marchal, Joseph", null);
list.append("Mata-Toledo, Ramon", null);
list.append("Norton, Michael", null);
list.append("Prieto-Díaz, Rubén", null);
list.append("Redwine, Samuel", null);
list.append("Tjaden, Brett", null);
list.append("Wang, Xunhua (Steve)", null);
list.addCommand(CANCEL_COMMAND);
list.addCommand(OK_COMMAND);
}
/**
* Construct an instance of this class
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static CallersScreen createInstance(ApplicationContext context)
{
if (instance == null) instance = new CallersScreen(context);
return instance;
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
instance = createInstance(context);
instance.enter();
return instance;
}
/**
* Get the Displayable associated with this AbstractState
*
* @returns The Displayable
*/
protected Displayable getDisplayable()
{
return list;
}
/**
* Handle a CANCEL_COMMAND
*/
public void handleCancel()
{
previousState.enter();
}
/**
* Handle an OK_COMMAND
*/
public void handleOK()
{
boolean[] selected;
WaitingScreen next;
int index, n;
String[] callers;
selected = new boolean[list.size()];
n = list.getSelectedFlags(selected);
if (n == 0)
{
callers = new String[1];
callers[0] = list.getString(0);
}
else
{
callers = new String[n];
index = 0;
for (int i=0; i<selected.length; i++)
{
if (selected[i])
{
callers[index] = list.getString(i);
index++;
}
}
}
next = WaitingScreen.createInstance(context);
next.setCallers(callers);
next.enter();
}
/**
* Set the previous state
*
* @param previous The previous AbstractState
*/
public void setPreviousState(AbstractState previous)
{
previousState = previous;
}
}
package phoneycall;
import java.util.*;
import javax.microedition.lcdui.*;
import auditory.*;
import gui.*;
/**
* The CallersScreen in PhoneyCall
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class WaitingScreen extends AbstractState
{
private AudioPlayer player;
private Form form;
private int delay, interval, number;
private Ringer ringer;
private String[] callers;
private StringItem text;
private Timer timer;
private static WaitingScreen instance;
/**
* Explicit Value Constructor
*
* @param context The ApplicationContext
*/
private WaitingScreen(ApplicationContext context)
{
super(context);
player = new AudioPlayer();
form = new Form("");
text = new StringItem("","Waiting for a call...");
form.append(text);
form.addCommand(CANCEL_COMMAND);
form.addCommand(OK_COMMAND);
timer = new Timer();
}
/**
* Construct an instance of this class
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static WaitingScreen createInstance(ApplicationContext context)
{
if (instance == null) instance = new WaitingScreen(context);
return instance;
}
/**
* Enter this instance of an AbstractScreen
*/
public void enter()
{
super.enter();
ringer = new Ringer();
timer.schedule(ringer, delay*1000, (interval*1000)/number);
}
/**
* Enter this AbstractState
*
* Specifically, construct an instance if necessary, perform any
* necessary operations, and call the instances enter() method
*
* @param context The ApplicationContext
* @return The (singleton) instance of this State
*/
public static AbstractState enter(ApplicationContext context)
{
instance = createInstance(context);
instance.enter();
return instance;
}
/**
* Get the Displayable associated with this AbstractState
*
* @returns The Displayable
*/
protected Displayable getDisplayable()
{
return form;
}
/**
* Handle a CANCEL_COMMAND
*/
public void handleCancel()
{
// Stop the audio
player.stop();
// Reset the message
text.setText("Waiting for a call...");
// Stop the TimerTask
ringer.cancel();
// Return to the CallCountScreen
CallCountScreen.enter(context);
}
/**
* Handle an OK_COMMAND
*/
public void handleOK()
{
// Stop the audio
player.stop();
// Reset the message
text.setText("Waiting for a call...");
if (number == 0) ringer.cancel();
}
/**
* Set the collection of callers
*
* @param callers The collection of callers
*/
public void setCallers(String[] callers)
{
this.callers = callers;
}
/**
* Set the delay
*
* @param delay The delay in minutes
*/
public void setDelay(int delay)
{
this.delay = delay;
}
/**
* Set the interval
*
* @param interval The interval in minutes
*/
public void setInterval(int interval)
{
this.interval = interval;
}
/**
* Set the number of calls
*
* @param number The number of calls
*/
public void setNumber(int number)
{
this.number = number;
}
/**
* The TimerTask used by the WaitingScreen
*
* Note: This is nested class (specifically, a named inner class)
*/
private class Ringer extends TimerTask
{
public void run()
{
number--;
if (number < 0) number = 0;
text.setText("Incoming call from "+callers[number]);
player.play("ringtone.wav");
}
}
}