001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.main;
028:
029: import com.sun.midp.lcdui.ForegroundEventProducer;
030:
031: import com.sun.midp.midlet.MIDletEventProducer;
032:
033: import com.sun.midp.suspend.SuspendDependency;
034:
035: import java.util.Timer;
036: import java.util.TimerTask;
037:
038: /**
039: * Represents the state of a running MIDlet and its Display so that objects
040: * do not have to be shared across Isolates. The states in this object are
041: * updated by the MIDletProxyList upon receiving a notification event.
042: * This class also provides methods for asynchronously changing a MIDlet's
043: * state.
044: */
045: public class MIDletProxy implements SuspendDependency {
046:
047: /** Constant for active state of a MIDlet. */
048: public static final int MIDLET_ACTIVE = 0;
049:
050: /** Constant for paused state of a MIDlet. */
051: public static final int MIDLET_PAUSED = 1;
052:
053: /** Constant for destroyed state of a MIDlet. */
054: public static final int MIDLET_DESTROYED = 2;
055:
056: /** Cached reference to the ForegroundEventProducer. */
057: private static ForegroundEventProducer foregroundEventProducer;
058:
059: /** Cached reference to the MIDletEventProducer. */
060: private static MIDletEventProducer midletEventProducer;
061:
062: /** ID given to this midlet by an external application manager. */
063: private int externalId;
064:
065: /** ID of the Isolate the MIDlet is running in. */
066: private int isolateId;
067:
068: /** ID of the MIDlet's Display. */
069: private int displayId;
070:
071: /** ID of the suite the MIDlet belongs to. */
072: private int suiteId;
073:
074: /** Class name of the MIDlet. */
075: private String className;
076:
077: /** Display name of the MIDlet to show the user. */
078: private String displayName;
079:
080: /**
081: * MIDlet life cycle state. Will be either MIDLET_ACTIVE, MIDLET_PAUSED,
082: * or MIDLET_DESTROYED.
083: */
084: private int midletState;
085:
086: /** Indicates that the midlet was just created. */
087: boolean wasNotActive;
088:
089: /** True if the MIDlet want's its Display in the foreground. */
090: private boolean wantsForegroundState;
091:
092: /** True if the MIDlet has the foreground at least once. */
093: private boolean requestedForeground;
094:
095: /** The display that is preempting this MIDlet. */
096: private MIDletProxy preempting;
097:
098: /** True if alert is waiting for the foreground. */
099: private boolean alertWaiting;
100:
101: /**
102: * The display to put in the foreground after this display stops
103: * preempting. If no display in this isolate had the foreground
104: * then this will be null.
105: */
106: private MIDletProxy preempted;
107:
108: /**
109: * Timer for the MIDlet proxy. Used when a midlet is hanging.
110: */
111: private Timer proxyTimer;
112:
113: /** Parent list. */
114: private MIDletProxyList parent;
115:
116: /**
117: * Initialize the MIDletProxy class. Should only be called by the
118: * MIDletProxyList.
119: *
120: * @param theForegroundEventProducer reference to the event producer
121: * @param theMIDletEventProducer reference to the event producer
122: */
123: static void initClass(
124: ForegroundEventProducer theForegroundEventProducer,
125: MIDletEventProducer theMIDletEventProducer) {
126:
127: foregroundEventProducer = theForegroundEventProducer;
128: midletEventProducer = theMIDletEventProducer;
129: }
130:
131: /**
132: * Construct a new MIDletProxy.
133: *
134: * @param theParentList parent MIDlet proxy list
135: * @param theExternalAppId ID of given by an external application manager
136: * @param theIsolateId ID of the Isolate the MIDlet is running in.
137: * @param theSuiteId ID of the suite MIDlet
138: * @param theClassName Class name of the MIDlet
139: * @param theDisplayName Display name of the MIDlet to show the user
140: * @param theMidletState MIDlet lifecycle state.
141: */
142: MIDletProxy(MIDletProxyList theParentList, int theExternalAppId,
143: int theIsolateId, int theSuiteId, String theClassName,
144: String theDisplayName, int theMidletState) {
145:
146: parent = theParentList;
147: externalId = theExternalAppId;
148: isolateId = theIsolateId;
149: suiteId = theSuiteId;
150: className = theClassName;
151: displayName = theDisplayName;
152: midletState = theMidletState;
153: wasNotActive = true;
154: }
155:
156: /**
157: * Get the external application ID used for forwarding changes.
158: *
159: * @return ID assigned by the external application manager
160: */
161: public int getExternalAppId() {
162: return externalId;
163: }
164:
165: /**
166: * Get the ID of the Isolate the MIDlet is running in. Public for testing
167: * purposes.
168: *
169: * @return ID of the Isolate the MIDlet is running in
170: */
171: public int getIsolateId() {
172: return isolateId;
173: }
174:
175: /**
176: * Sets the ID of the MIDlet's Display.
177: *
178: * @param id of the MIDlet's Display
179: */
180: void setDisplayId(int id) {
181: displayId = id;
182: }
183:
184: /**
185: * Get the ID of the MIDlet's Display. Public for testing purposes.
186: *
187: * @return ID of the MIDlet's Display
188: */
189: public int getDisplayId() {
190: return displayId;
191: }
192:
193: /**
194: * Get the ID of the MIDlet's suite.
195: *
196: * @return ID of the MIDlet's suite
197: */
198: public int getSuiteId() {
199: return suiteId;
200: }
201:
202: /**
203: * Get the class name of the MIDlet.
204: *
205: * @return class name of the MIDlet
206: */
207: public String getClassName() {
208: return className;
209: }
210:
211: /**
212: * Get the Display name of the MIDlet.
213: *
214: * @return Display name of the MIDlet
215: */
216: public String getDisplayName() {
217: return displayName;
218: }
219:
220: /**
221: * Set the MIDlet cycle state. Called by the
222: * MIDlet proxy list when it receives an event from the MIDlet
223: * to update this value.
224: *
225: * @param newMidletState new MIDlet state
226: */
227: void setMidletState(int newMidletState) {
228: midletState = newMidletState;
229: }
230:
231: /**
232: * Get the MIDlet lifecycle state.
233: *
234: * @return MIDlet state
235: */
236: public int getMidletState() {
237: return midletState;
238: }
239:
240: /**
241: * Set the wants foreground state in the proxy. Called by the
242: * MIDlet proxy list when it receives an event from the MIDlet's
243: * display to update this value.
244: *
245: * @param newWantsForeground new wants foreground value.
246: * @param isAlert true if the displayable requesting the foreground,
247: * is an Alert, this parameter is ignored if newWantsForeground
248: * is false
249: */
250: void setWantsForeground(boolean newWantsForeground, boolean isAlert) {
251: wantsForegroundState = newWantsForeground;
252:
253: if (newWantsForeground) {
254: requestedForeground = true;
255: alertWaiting = isAlert;
256: } else {
257: alertWaiting = false;
258: }
259: }
260:
261: /**
262: * Check if the MIDlet want's its Display in the foreground.
263: *
264: * @return true if the MIDlet want's its Display in the foreground
265: */
266: public boolean wantsForeground() {
267: return wantsForegroundState;
268: }
269:
270: /**
271: * Check if the MIDlet has not created its display.
272: *
273: * @return true if the MIDlet has no display.
274: */
275: public boolean noDisplay() {
276: return displayId == 0;
277: }
278:
279: /**
280: * Check if the MIDlet has not set a displayable in its display.
281: * Used by foreground selector to determine if the MIDlet it is
282: * about to put in the foreground will draw the screen.
283: *
284: * @return true if the MIDlet has no displayable.
285: */
286: public boolean noDisplayable() {
287: return !requestedForeground;
288: }
289:
290: /**
291: * Set the proxy of the display that is preempting this MIDlet.
292: *
293: * @param preemptingDisplay the preempting display
294: */
295: void setPreemptingDisplay(MIDletProxy preemptingDisplay) {
296: // Turn on the user notification status for this proxy
297: if (preemptingDisplay != null) {
298: alertWaiting = true;
299: } else {
300: if (preempting != null) {
301: /*
302: * There could be a proxy timer waiting to destroy the
303: * isolate if the user ended the alert with the end MIDlet
304: * button, so cancel the timer.
305: */
306: preempting.setTimer(null);
307: }
308:
309: alertWaiting = false;
310: }
311:
312: preempting = preemptingDisplay;
313: }
314:
315: /**
316: * Get the proxy of the display that is preempting this MIDlet.
317: *
318: * @return the preempting display
319: */
320: MIDletProxy getPreemptingDisplay() {
321: return preempting;
322: }
323:
324: /**
325: * Set the proxy of the MIDlet that should get the foreground
326: * after preempting is done.
327: *
328: * @param preemptedDisplay the preempted display
329: */
330: void setPreemptedMidlet(MIDletProxy preemptedDisplay) {
331: preempted = preemptedDisplay;
332: }
333:
334: /**
335: * Get the proxy of the MIDlet that should get the foreground
336: * after preempting is done.
337: *
338: * @return the preempted display or null for none
339: */
340: MIDletProxy getPreemptedMidlet() {
341: return preempted;
342: }
343:
344: /**
345: * Called to determine if alert is waiting for the foreground.
346: *
347: * @return true if an alert of the MIDlet is waiting in background.
348: */
349: public boolean isAlertWaiting() {
350: return alertWaiting;
351: }
352:
353: /**
354: * Asynchronously change the MIDlet's state to active.
355: *
356: * This method does NOT change the state in the proxy, but
357: * sends a activate MIDlet event to the MIDlet's Display.
358: * The state in the proxy is only update when the MIDlet sends
359: * a MIDlet activated event to the proxy list.
360: */
361: public void activateMidlet() {
362: if (midletState != MIDLET_DESTROYED) {
363: wasNotActive = false;
364: midletEventProducer.sendMIDletActivateEvent(isolateId,
365: className);
366: }
367: }
368:
369: /**
370: * Asynchronously change the MIDlet's state to paused.
371: *
372: * This method does NOT change the state in the proxy, but
373: * sends a pause MIDlet event to the MIDlet's Display.
374: * The state in the proxy is only update when the MIDlet sends
375: * a MIDlet paused event to the proxy list.
376: */
377: public void pauseMidlet() {
378: if (midletState != MIDLET_DESTROYED) {
379: midletEventProducer.sendMIDletPauseEvent(isolateId,
380: className);
381: }
382: }
383:
384: /**
385: * Terminates ther MIDlet if it is neither paused nor destroyed.
386: */
387: public void terminateNotPausedMidlet() {
388: if (midletState != MIDLET_DESTROYED
389: && midletState != MIDLET_PAUSED) {
390: MIDletProxyUtils.terminateMIDletIsolate(this , parent);
391: }
392: }
393:
394: /**
395: * Asynchronously change the MIDlet's state to destroyed.
396: *
397: * This method does NOT change the state in the proxy, but
398: * sends request to destroy MIDlet event to the AMS.
399: * The state in the proxy is only update when the MIDlet sends
400: * a MIDlet destroyed event to the proxy list.
401: */
402: public void destroyMidlet() {
403: if (midletState != MIDLET_DESTROYED) {
404: if (getTimer() != null) {
405: // A destroy MIDlet event has been sent.
406: return;
407: }
408:
409: MIDletDestroyTimer.start(this , parent);
410:
411: midletEventProducer.sendMIDletDestroyEvent(isolateId,
412: className);
413: }
414: }
415:
416: /** Process a MIDlet destroyed notification. */
417: void destroyedNotification() {
418: setTimer(null);
419: setMidletState(MIDLET_DESTROYED);
420: }
421:
422: /**
423: * Notify the midlet's display of a foreground change. Called by
424: * the MIDlet proxy list to notify the old and new foreground displays
425: * of a foreground change.
426: *
427: * @param hasForeground true if the target is being put in the foreground
428: */
429: void notifyMIDletHasForeground(boolean hasForeground) {
430: if (hasForeground) {
431: alertWaiting = false;
432: foregroundEventProducer.sendDisplayForegroundNotifyEvent(
433: isolateId, displayId);
434: } else {
435: foregroundEventProducer.sendDisplayBackgroundNotifyEvent(
436: isolateId, displayId);
437: }
438: }
439:
440: /**
441: * Sets the timer object
442: *
443: * @param t Timer object
444: */
445: void setTimer(Timer t) {
446: proxyTimer = t;
447: }
448:
449: /**
450: * Gets the timer object
451: *
452: * @return Timer
453: */
454: Timer getTimer() {
455: return proxyTimer;
456: }
457:
458: /**
459: * Print the state of the proxy.
460: *
461: * @return printable representation of the state of this object
462: */
463: public String toString() {
464: return "MIDletProxy: suite id = " + suiteId
465: + "\n class name = " + className
466: + "\n display name = " + displayName
467: + "\n isolate id = " + isolateId + ", display id = "
468: + displayId + ", midlet state = " + midletState
469: + ", wantsForeground = " + wantsForegroundState
470: + ", requestedForeground = " + requestedForeground
471: + "\n alertWaiting = " + alertWaiting;
472: }
473: }
474:
475: /**
476: * If the MIDlet is hanging this class will start a
477: * timer and terminate the MIDlet when the timer
478: * expires. The timer will not work in SVM mode.
479: */
480: class MIDletDestroyTimer {
481: /** Timeout to let MIDlet destroy itself. */
482: private static final int TIMEOUT = 1000 * Configuration
483: .getIntProperty("destoryMIDletTimeout", 5);
484:
485: /**
486: * Starts timer for the specified MIDlet (proxy) .
487: *
488: * @param mp MIDletProxy to terminate if not destroyed in time
489: * @param mpl the MIDletProxyList
490: */
491: static void start(final MIDletProxy mp, final MIDletProxyList mpl) {
492: Timer timer = new Timer();
493: mp.setTimer(timer);
494:
495: TimerTask task = new TimerTask() {
496: /** Terminates MIDlet isolate and updates the proxy list. */
497: public void run() {
498: if (mp.getTimer() != null) {
499: MIDletProxyUtils.terminateMIDletIsolate(mp, mpl);
500: }
501: cancel();
502: }
503: };
504:
505: timer.schedule(task, TIMEOUT);
506: }
507: }
|