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: package com.sun.midp.main;
027:
028: import java.util.*;
029:
030: /**
031: * This class controls which MIDlet's display is in the foreground.
032: * Running only in the AMS Isolate (0) the controller consulted by the MIDlet
033: * proxy list for any foreground when various state changes occur in a MIDlet.
034: * The display controller automatically selects the next foreground if
035: * needed.
036: * <p>
037: * From the user perspective when the last MIDlet the user launched sets its
038: * current displayable for the first time, that MIDlet should automatically
039: * get the foreground (see the midletCreated and foregroundRequest methods).
040: * <p>
041: * A MIDlet that is paused or destroyed is treated as if it has requested the
042: * background as described above.
043: */
044: class DisplayController {
045: /**
046: * The last MIDlet added to the MIDlet proxy list, but has not requested
047: * to be in the foreground.
048: */
049: protected MIDletProxy lastMidletCreated;
050:
051: /** Cache of the MIDlet proxy list reference. */
052: protected MIDletProxyList midletProxyList;
053:
054: /** What objects want to listen. */
055: private Vector listeners = new Vector(1, 1);
056:
057: /**
058: * Construct a DisplayController with a reference to the ProxyList.
059: *
060: * @param theMIDletProxyList reference to the MIDlet proxy list
061: */
062: protected DisplayController(MIDletProxyList theMIDletProxyList) {
063: midletProxyList = theMIDletProxyList;
064: }
065:
066: /**
067: * Add a listener.
068: *
069: * @param listener DisplayController listener
070: */
071: public void addListener(DisplayControllerListener listener) {
072: listeners.addElement(listener);
073: }
074:
075: /**
076: * Remove a listener for DisplayController.
077: *
078: * @param listener DisplayController listener
079: */
080: public void removeListener(DisplayControllerListener listener) {
081: listeners.removeElement(listener);
082: }
083:
084: /**
085: * Update the last MIDlet created field so when the wantsForeground
086: * field of the MIDletProxy is updated to be true, the MIDlet can
087: * be automatically put into the foreground.
088: * <p>
089: * Called when a MIDlet is created to the proxy list.
090: *
091: * @param midlet The proxy of the MIDlet being created
092: */
093: void midletCreated(MIDletProxy midlet) {
094: lastMidletCreated = midlet;
095: }
096:
097: /**
098: * Called when a MIDlet is move to active state.
099: *
100: * @param midlet The proxy of the MIDlet being activated
101: *
102: * @return Proxy of the next foreground MIDlet, may be the foreground
103: * MIDlet if the foreground should not change
104: */
105: MIDletProxy midletActive(MIDletProxy midlet) {
106: return midletProxyList.getForegroundMIDlet();
107: }
108:
109: /**
110: * Handles any possible foreground changes due the state of a MIDlet
111: * changing to paused.
112: * <p>
113: * Treat this state change as a background request.
114: * <p>
115: * Called when the state of a MIDlet in the MIDlet proxy list is paused.
116: *
117: * @param midlet The proxy of the MIDlet that was updated
118: *
119: * @return Proxy of the next foreground MIDlet, may be the foreground
120: * MIDlet if the foreground should not change
121: */
122: MIDletProxy midletPaused(MIDletProxy midlet) {
123: return backgroundRequest(midlet);
124: }
125:
126: /**
127: * If the removed MIDlet is the foreground MIDlet find a new
128: * foreground MIDlet. After clearing the last midlet created, treat this
129: * state change as background request.
130: * <p>
131: * Called when a MIDlet is removed from the proxy list.
132: *
133: * @param midlet The proxy of the removed MIDlet
134: *
135: * @return Proxy of the next foreground MIDlet, may be the foreground
136: * MIDlet if the foreground should not change
137: */
138: MIDletProxy midletDestroyed(MIDletProxy midlet) {
139: clearLastMidletCreated(midlet);
140:
141: return backgroundRequest(midlet);
142: }
143:
144: /**
145: * Handles MIDlet foreground requests.
146: * <p>
147: * If proxy being updated belongs last MIDlet created in the proxy list,
148: * then put the MIDlet in the foreground.
149: * <p>
150: * If there is no foreground MIDlet or the foreground MIDlet does not
151: * want the foreground or the foreground MIDlet is paused, then put the
152: * MIDlet in the foreground.
153: *
154: * @param midlet The proxy of the MIDlet that was updated
155: *
156: * @return Proxy of the next foreground MIDlet, may be the foreground
157: * MIDlet if the foreground should not change
158: */
159: MIDletProxy foregroundRequest(MIDletProxy midlet) {
160: MIDletProxy foreground;
161:
162: /*
163: * When the last MIDlet started wants the foreground automatically
164: * put in the foreground this time only.
165: */
166: if (midlet == lastMidletCreated) {
167: return midlet;
168: }
169:
170: foreground = midletProxyList.getForegroundMIDlet();
171: if (foreground == null
172: || !foreground.wantsForeground()
173: || foreground.getMidletState() == MIDletProxy.MIDLET_PAUSED) {
174: return midlet;
175: }
176:
177: // don't change the foreground
178: return foreground;
179: }
180:
181: /**
182: * Handles MIDlet background requests.
183: * <p>
184: * If the MIDlet is requesting to be put in the background is the
185: * foreground MIDlet, then find a MIDlet to bring to the foreground
186: * (see the findNextForeground method).
187: *
188: * @param midlet The proxy of the MIDlet that was updated
189: *
190: * @return Proxy of the next foreground MIDlet, may be the foreground
191: * MIDlet if the foreground should not change
192: */
193: MIDletProxy backgroundRequest(MIDletProxy midlet) {
194: MIDletProxy foreground = midletProxyList.getForegroundMIDlet();
195:
196: if (midlet != foreground) {
197: // not in the foreground, so don't change the foreground
198: return foreground;
199: }
200:
201: return findNextForegroundMIDlet();
202: }
203:
204: /**
205: * Find a MIDlet that wants the foreground. If none wants the foreground
206: * then find one that is not paused, if no find one that is paused
207: * and wants the foreground, then find one that is paused.
208: *
209: * @return new foreground task or null
210: */
211: private MIDletProxy findNextForegroundMIDlet() {
212: Enumeration midlets;
213:
214: // find the first task that is active and wants foreground
215: midlets = midletProxyList.getMIDlets();
216: while (midlets.hasMoreElements()) {
217: MIDletProxy current = (MIDletProxy) midlets.nextElement();
218:
219: if (current.getMidletState() != MIDletProxy.MIDLET_ACTIVE) {
220: continue;
221: }
222:
223: if (current.wantsForeground()) {
224: return current;
225: }
226: }
227:
228: // find the first task that is active
229: midlets = midletProxyList.getMIDlets();
230: while (midlets.hasMoreElements()) {
231: MIDletProxy current = (MIDletProxy) midlets.nextElement();
232:
233: if (current.getMidletState() != MIDletProxy.MIDLET_ACTIVE) {
234: return current;
235: }
236: }
237:
238: // find the first task that is paused and wants the foreground
239: midlets = midletProxyList.getMIDlets();
240: while (midlets.hasMoreElements()) {
241: MIDletProxy current = (MIDletProxy) midlets.nextElement();
242:
243: if (current.getMidletState() != MIDletProxy.MIDLET_PAUSED) {
244: continue;
245: }
246:
247: if (current.wantsForeground()) {
248: return current;
249: }
250: }
251:
252: // find the first task that is paused
253: midlets = midletProxyList.getMIDlets();
254: while (midlets.hasMoreElements()) {
255: MIDletProxy current = (MIDletProxy) midlets.nextElement();
256:
257: if (current.getMidletState() != MIDletProxy.MIDLET_PAUSED) {
258: return current;
259: }
260: }
261:
262: return null;
263: }
264:
265: /**
266: * Request a transfer of the foreground from one MIDlet to another.
267: * The transfer only succeeds if the current foreground is the "from"
268: * MIDlet.
269: * @param origin the MIDletProxy from which the FG should transfer from
270: * @param target the MIDletProxy to which the FG should transfer to
271: * @return the choice about which to become the FG
272: */
273: MIDletProxy transferRequest(MIDletProxy origin, MIDletProxy target) {
274: MIDletProxy foreground = midletProxyList.getForegroundMIDlet();
275: if (origin == foreground) {
276: // Foreground is the requesting MIDlet, change to target
277: return target;
278: }
279:
280: // The foreground is not the requesting origin; don't change
281: return foreground;
282: }
283:
284: /**
285: * Called to process a preempt event. The default is to preempt the
286: * foreground.
287: *
288: * @param preempting proxy of the preempting MIDlet to be put in the
289: * foreground when a preempted MIDlet gets the foreground or to be
290: * put in the foreground directly.
291: *
292: * @return Proxy of the next foreground MIDlet, may be the foreground
293: * MIDlet if the foreground should not change
294: *
295: */
296: MIDletProxy startPreempting(MIDletProxy preempting) {
297: MIDletProxy foreground;
298:
299: foreground = midletProxyList.getForegroundMIDlet();
300: if (foreground != null) {
301: preempting.setPreemptedMidlet(foreground);
302: foreground.setPreemptingDisplay(preempting);
303: }
304:
305: return preempting;
306: }
307:
308: /**
309: * End the preempt an Isolate's displays.
310: *
311: * @param isolateId isolate ID of display that done preempting
312: * @param displayId display ID of display that done preempting
313: *
314: * @return Proxy of the next foreground MIDlet, may be the foreground
315: * MIDlet if the foreground should not change
316: *
317: */
318: MIDletProxy endPreempting(int isolateId, int displayId) {
319: Enumeration midlets;
320: MIDletProxy foreground;
321: MIDletProxy preempted;
322: MIDletProxy preempting = null;
323:
324: /*
325: * Stop preempting all of the MIDlets that were preempted.
326: */
327: midlets = midletProxyList.getMIDlets();
328: while (midlets.hasMoreElements()) {
329: MIDletProxy current = (MIDletProxy) midlets.nextElement();
330: MIDletProxy temp;
331:
332: temp = current.getPreemptingDisplay();
333: if (temp == null) {
334: continue;
335: }
336:
337: if (temp.getIsolateId() != isolateId) {
338: continue;
339: }
340:
341: if (temp.getDisplayId() != displayId) {
342: continue;
343: }
344:
345: preempting = temp;
346:
347: current.setPreemptingDisplay(null);
348: midletProxyList.notifyListenersOfProxyUpdate(current,
349: MIDletProxyListListener.PREEMPTING_DISPLAY);
350: }
351:
352: foreground = midletProxyList.getForegroundMIDlet();
353: if (foreground == null) {
354: return null;
355: }
356:
357: if (preempting == null) {
358: return foreground;
359: }
360:
361: preempted = preempting.getPreemptedMidlet();
362:
363: // if the preempting display is not in the foreground then do nothing
364: if (foreground != preempting) {
365: return foreground;
366: }
367:
368: preempted = preempting.getPreemptedMidlet();
369:
370: if (preempted != null) {
371: return preempted;
372: }
373:
374: return foreground;
375: }
376:
377: /**
378: * Call to notify that foreground MIDlet is changing and give the
379: * display controller a chance to preempt the change.
380: * Also the last MIDlet created state will be reset.
381: * <p>
382: * If the MIDlet to get the foreground is paused, then activate it.
383: *
384: * @param midlet proxy of the MIDlet to be put in the foreground
385: *
386: * @return Proxy of the next foreground MIDlet, may be the foreground
387: * MIDlet if the foreground should not change
388: */
389: MIDletProxy foregroundMidletChanging(MIDletProxy midlet) {
390: MIDletProxy preempting;
391:
392: if (midlet == null) {
393: return null;
394: }
395:
396: preempting = midlet.getPreemptingDisplay();
397: if (preempting != null) {
398: return preempting;
399: }
400:
401: clearLastMidletCreated(midlet);
402:
403: if (midlet.getMidletState() == MIDletProxy.MIDLET_PAUSED) {
404: midlet.activateMidlet();
405: }
406:
407: return midlet;
408: }
409:
410: /**
411: * Clear the last MIDlet created, if it is one given.
412: *
413: * @param midlet a proxy of the MIDlet that may be the last MIDlet created
414: */
415: private void clearLastMidletCreated(MIDletProxy midlet) {
416: if (lastMidletCreated == midlet) {
417: lastMidletCreated = null;
418: }
419: }
420:
421: /**
422: * Called to process a select foreground event. Processing this event
423: * only needs to be done when application MIDlets are allowed to run
424: * concurrently. In SVM mode the display controller returns
425: * foreground MIDlet.
426: *
427: * @param onlyFromLaunchedList true if midlet should
428: * be selected from the list of already launched midlets,
429: * if false then possibility to launch midlet is needed.
430: * @return Proxy of the next foreground MIDlet, may be the foreground
431: * MIDlet if the foreground should not change
432: */
433: MIDletProxy selectForeground(boolean onlyFromLaunchedList) {
434: notifyListenersOfSelectForeground(onlyFromLaunchedList);
435: return midletProxyList.getForegroundMIDlet();
436: }
437:
438: /**
439: * Notify the listeners of the display controller that foreground
440: * selection ui should be launched.
441: *
442: * @param onlyFromLaunchedList true if midlet should
443: * be selected from the list of already launched midlets,
444: * if false then possibility to launch midlet is needed.
445: */
446: void notifyListenersOfSelectForeground(boolean onlyFromLaunchedList) {
447: for (int i = listeners.size() - 1; i >= 0; i--) {
448: DisplayControllerListener listener = (DisplayControllerListener) listeners
449: .elementAt(i);
450:
451: listener.selectForeground(onlyFromLaunchedList);
452: }
453: }
454: }
|