Fields Summary |
---|
private MIDletSuite | midletSuitethe current MIDlet suite |
private MIDletState[] | midletsarray of MIDlets |
private int | nmidletscurrent number of MIDlets [0..n-1] |
private int | scanIndexnext index to be scanned by selectForeground |
private com.sun.midp.lcdui.DisplayManager | displayManagerdisplay manager |
private boolean | systemShutdownFlag to indicate if the system was shutdown. |
private static Object | mutexused to wait for MIDlet state changes |
private static Scheduler | schedulerthe manager of all MIDlets |
private Thread | schedulerThreadthe thread on which the scheduler is active |
Methods Summary |
---|
public void | destroyMIDlet(javax.microedition.midlet.MIDlet midlet)Destroy the MIDlet given midlet. Return to the control to
AMS if there are no another active MIDlets in the
scheduled. This is a system callback which
allows a user to forcibly exit a running MIDlet in cases
where it is necessary (such as a rogue MIDlet which does
not provide exit capability).
MIDletState state = MIDletStateMap.getState(midlet);
state.setState(MIDletState.DESTROY_PENDING);
|
private int | findMIDletByClass(MIDletState m)Find a MIDlet in the list by it class.
Only a single MIDlet of a class can be active at
a time.
Must be called synchronized on the mutex.
// Find it in the list
for (int i = 0; i < nmidlets; i++) {
if (m.getMIDlet().getClass() ==
midlets[i].getMIDlet().getClass()) {
return i;
}
}
return -1;
|
private com.sun.midp.lcdui.DisplayManager | getDisplayManager()Get the display manager.
if (displayManager == null) {
displayManager = DisplayManagerFactory.getDisplayManager();
}
return displayManager;
|
public MIDletSuite | getMIDletSuite()Provides a MIDletProxy with a mechanism to retrieve
MIDletSuite being scheduled.
return midletSuite;
|
protected java.lang.Object | getMutex()Return the mutex for synchronization and notification of changes
to a MIDlets state.
It is used by MIDlets when they are changing states.
It is the mutex used for all state changes.
return mutex;
|
public static synchronized com.sun.midp.midlet.Scheduler | getScheduler()Get the Scheduler that manages the lifecycle states MIDlets.
If the instance of the Scheduler has already been created
it is returned. If not it is created from the value of
the "com.sun.midp.midlet.scheduler" property. If that property
is null the default scheduler (this class) is instantiated.
The instance becomes the Scheduler for this process
/*
* If not scheduler has been created, create one now.
* If the scheduler class has been overridden use it.
*/
if (scheduler == null) {
String prop =
Configuration.getProperty("com.sun.midp.midlet.scheduler");
if (prop != null) {
Class c;
try {
c = Class.forName(prop);
} catch (Throwable ex) {
throw new Error("A scheduler class cannot be loaded " +
"from the value of property " +
"com.sun.midp.midlet.scheduler");
}
try {
scheduler = (Scheduler)c.newInstance();
} catch (Throwable ex) {
throw new Error("The construction of " + prop +
" instance failed");
}
} else {
/* This is the default scheduler class */
scheduler = new Scheduler();
}
}
return scheduler;
|
public boolean | isDispatchThread()Returns true if the current thread is the Scheduler's thread.
// NOTE: This will have to be removed when Display
// changes queued in the event handler
return (Thread.currentThread() == schedulerThread);
|
public boolean | isScheduled(java.lang.String name)Check if the named MIDlet has already been instantiated.
boolean found = false;
synchronized (mutex) {
for (int i = 0; i < nmidlets; i++) {
if (midlets[i].getMIDlet().getClass().getName().equals(name)) {
found = true;
break;
}
}
}
return found;
|
public void | pauseMIDlet(javax.microedition.midlet.MIDlet midlet)Pause the current foreground MIDlet and return to the
AMS or "selector" to possibly run another MIDlet in the
currently active suite. Currently, the RI does not support
running multiple MIDlets, but if it did, this system
callback would allow it. The listener should not deactivate
the display of the MIDlet.
MIDletState state = MIDletStateMap.getState(midlet);
state.setState(MIDletState.PAUSE_PENDING);
|
private static void | printException(java.lang.String msg, java.lang.Exception ex)Print an exception with a reason.
Should be logged instead.
try {
System.out.println(msg);
if (ex.getMessage() == null) {
System.out.println(ex);
}
ex.printStackTrace();
} catch (Exception e) {
}
|
protected void | register(javax.microedition.midlet.MIDlet midlet)Register a MIDlet being constructed.
synchronized (mutex) {
MIDletState state = MIDletStateMap.getState(midlet);
/*
* If a MIDlet of the same class is already running
* Make the existing MIDlet current so that schedule() will run it
*/
int i = findMIDletByClass(state);
if (i >= 0) {
state.setState(MIDletState.DESTROY_PENDING);
// Fall into adding it to the list so destroyApp
// can be called at a reasonable time.
}
// Grow the list if necessary
if (nmidlets >= midlets.length) {
MIDletState[] n = new MIDletState[nmidlets+5];
System.arraycopy(midlets, 0, n, 0, nmidlets);
midlets = n;
}
// Add it to the end of the list
midlets[nmidlets++] = state;
mutex.notify();
}
|
public boolean | schedule(MIDletSuite aMidletSuite)Run MIDlets until there are none.
Handle any pending state transitions of any MIDlet.
If there are none, wait for transitions.
If there is no foreground MIDlet select one that is ACTIVE and
has setCurrent != null.
If the foreground MIDlet changes from the ACTIVE_FOREGROUND state
it automatically looses the foreground and and new one is selected.
if (midletSuite != null) {
throw new RuntimeException(
"There is already a MIDlet Suite scheduled.");
}
// NOTE: This will have to be removed when Display
// changes queued in the event handler
schedulerThread = Thread.currentThread();
getDisplayManager().addSystemEventListener(this);
midletSuite = aMidletSuite;
register(
MIDletState.createMIDlet(midletSuite.getInitialMIDletClassname()));
/*
* Until there are no MIDlets
* Scan all the MIDlets looking for state changes.
*/
while (nmidlets > 0) {
try {
MIDletState curr;
int state;
synchronized (mutex) {
/*
* Find the highest priority state of any MIDlet and
* process, but do not hold the lock while processing
* to avoid deadlocks with LCDUI and event handling.
* Perform state changes with a lock so
* no state changes are lost.
*/
curr = selectByPriority();
state = curr.getState();
switch (state) {
case MIDletState.ACTIVE:
// fall through
case MIDletState.PAUSED:
// Wait for some change in the state of a MIDlet
// that needs attention
try {
mutex.wait();
} catch (InterruptedException e) {
}
continue;
case MIDletState.PAUSED_RESUME:
// fall through
case MIDletState.ACTIVE_PENDING:
// Start the MIDlet
curr.setStateWithoutNotify(MIDletState.ACTIVE);
break;
case MIDletState.PAUSE_PENDING:
// The display manager wants the MIDlet paused
curr.setStateWithoutNotify(MIDletState.PAUSED);
break;
case MIDletState.DESTROY_PENDING:
curr.setStateWithoutNotify(MIDletState.DESTROYED);
break;
case MIDletState.DESTROYED:
unregister(curr);
break;
default:
throw new Error("Illegal MIDletState state " +
curr.getState());
}
}
/* perform work that may block outside of the mutex. */
switch (state) {
case MIDletState.PAUSED_RESUME:
getDisplayManager().activate(this, curr.getMIDlet());
// fall through
case MIDletState.ACTIVE_PENDING:
try {
curr.startApp();
} catch (Exception ex) {
printException("startApp threw an Exception", ex);
curr.setState(MIDletState.DESTROY_PENDING);
}
break;
case MIDletState.PAUSE_PENDING:
try {
curr.pauseApp();
} catch (Exception ex) {
printException("pauseApp threw an Exception", ex);
curr.setState(MIDletState.DESTROY_PENDING);
}
break;
case MIDletState.DESTROY_PENDING:
// If the MIDlet is in the DESTROY_PENDING state
// call its destroyApp method to clean it up.
try {
// Tell the MIDlet to cleanup.
curr.destroyApp(true);
} catch (MIDletStateChangeException ex) {
// Ignore the exception
} catch (Exception ex) {
printException("destroyApp threw an Exception",
ex);
}
break;
case MIDletState.DESTROYED:
getDisplayManager().deactivate(curr.getMIDlet());
break;
}
} catch (Exception ex) {
System.out.println("Exception in schedule");
ex.printStackTrace();
}
}
midletSuite.saveSettings();
midletSuite = null;
getDisplayManager().releaseSystemEventListener(this);
return !systemShutdown;
|
public void | scheduleMIDlet(javax.microedition.midlet.MIDlet midlet)Schedule a MIDlet from outside of the package.
midletSuite.checkIfPermissionAllowed(Permissions.AMS);
register(midlet);
|
private MIDletState | selectByPriority()Look through the current MIDlets and select one to
be processed.
Note: that this method is called while synchronized on "mutex".
MIDletState found = null; // Chosen MIDletState
int state = -1; // the state of the chosen MIDlet
/*
* Find the most desirable MIDlet based on its state
* The higher state values are preferred because they
* are needed for cleanup.
*/
for (int i = nmidlets-1; i >= 0; i--) {
// make sure index is inside current array, favoring the end
if (scanIndex < 0 || scanIndex >= nmidlets)
scanIndex = nmidlets-1;
// Pick this MIDlet if the state is higher priority
int s = midlets[scanIndex].getState();
if (s > state) {
found = midlets[scanIndex];
state = s;
}
scanIndex--;
}
return found;
|
public void | shutdown()Shutdown all running MIDlets and prepare the MIDP runtime
to exit completely.
synchronized (mutex) {
systemShutdown = true;
for (int i = 0; i < nmidlets; i++) {
if (midlets[i].getState() != MIDletState.DESTROYED) {
midlets[i].
setStateWithoutNotify(MIDletState.DESTROY_PENDING);
}
}
mutex.notify();
}
|
public void | startMIDlet(javax.microedition.midlet.MIDlet midlet)Start the currently suspended state. This is a result
of the underlying system returning control to MIDP.
Any previously paused foreground MIDlet will be restarted
and the Display will be refreshed. The listener should not activate
the display of the MIDlet since this will be done automatically.
MIDletState state = MIDletStateMap.getState(midlet);
state.setState(MIDletState.ACTIVE_PENDING);
|
private void | unregister(MIDletState m)Remove a MIDlet from the list if it is there,
otherwise ignore the request.
Call only while synchronized on mutex.
// Find it in the list and switch the last one for it.
for (int i = 0; i < nmidlets; i++) {
if (m == midlets[i]) {
// Switch the last MIDlet into that offset.
midlets[i] = midlets[nmidlets-1];
// null out from array and remove from map to allow for GC
midlets[--nmidlets] = null;
break;
}
}
|