The J2ME Mobile Information Device Profile
Using the State Pattern |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
MIDlet
s 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"); } } }