0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package com.sun.midp.main;
0028:
0029: import java.util.*;
0030:
0031: import com.sun.midp.events.EventQueue;
0032:
0033: import com.sun.midp.midlet.MIDletStateHandler;
0034: import com.sun.midp.midlet.MIDletSuite;
0035:
0036: import com.sun.midp.security.Permissions;
0037: import com.sun.midp.security.SecurityToken;
0038: import com.sun.midp.security.ImplicitlyTrustedClass;
0039: import com.sun.midp.security.SecurityInitializer;
0040:
0041: import com.sun.midp.suspend.SuspendSystem;
0042: import com.sun.midp.suspend.SuspendSystemListener;
0043:
0044: /**
0045: * Manages a list of MIDlet proxies, each proxy representing a running MIDlet
0046: * and tracks which MIDlet has the foreground display, the list only available
0047: * to objects running in the AMS isolate.
0048: * <p>
0049: * The list is updated upon receiving events. See the process method for event
0050: * processing.
0051: * <p>
0052: * Objects can listen (see MIDletProxyListListener) to the list for additions,
0053: * updates to proxies, and removals as will as set foreground events and
0054: * select foreground events.
0055: * <p>
0056: * This class also provides a shutdown method and processes a shutdown event
0057: * to enable the method be used by native code.
0058: *
0059: */
0060: public class MIDletProxyList implements MIDletControllerEventConsumer,
0061: SuspendSystemListener {
0062:
0063: /** MIDletProxy added constant. */
0064: static final int PROXY_ADDED = 0;
0065:
0066: /** MIDletProxy removed constant. */
0067: static final int PROXY_REMOVED = 1;
0068:
0069: /** The one and only MIDlet proxy list. */
0070: private static MIDletProxyList midletProxyList;
0071:
0072: /** True when the system is shutting down. */
0073: private static boolean shutdownFlag;
0074:
0075: /** What objects should get list changes. */
0076: private Vector listeners = new Vector(2, 2);
0077:
0078: /** Vector to hold MIDlet proxies. */
0079: private Vector midletProxies = new Vector(5, 5);
0080:
0081: /** The foreground MIDlet. */
0082: private MIDletProxy foregroundMidlet;
0083:
0084: /** The one and only displayController. */
0085: private DisplayController displayController;
0086:
0087: /** True if all midlets are paused, false - otherwise */
0088: private boolean allPaused; // = false
0089:
0090: /**
0091: * MIDlet proxy whose peer application runs in the AMS isolate. Should
0092: * be accessed through findAmsProxy(), may be invalid otherwise.
0093: */
0094: private MIDletProxy amsProxy;
0095:
0096: /**
0097: * Class registered in SecurityInitializer that identifies this
0098: * implementation permissions for accessing restricted API's
0099: */
0100: private static class SecurityTrusted implements
0101: ImplicitlyTrustedClass {
0102: }
0103:
0104: /** Security token for provileged access to restricted API's. */
0105: private static SecurityToken classSecurityToken = SecurityInitializer
0106: .requestToken(new SecurityTrusted());
0107:
0108: /**
0109: * Called by the MIDlet suite loader in AMS Isolate to intialize the
0110: * midletProxy list. Shall be called only by MIDletSuiteLoader's main().
0111: *
0112: * @param theMIDletProxyList proxy list instance to be used
0113: * as MIDlet controller container
0114: *
0115: * Should only be called in the AMS Isolate.
0116: */
0117: static void initClass(MIDletProxyList theMIDletProxyList) {
0118:
0119: /*
0120: TBD: the code below is commented until
0121: the issue with non-static Logging.assertTrue
0122: will be fixed !
0123:
0124: Logging.assertTrue(theMIDletProxyList != null,
0125: "theMIDletProxyList must be non-null");
0126: Logging.assertTrue(midletProxyList == null,
0127: "midletProxyList must be initialized only once");
0128: */
0129: midletProxyList = theMIDletProxyList;
0130: }
0131:
0132: /**
0133: * Get a reference to the MIDlet proxy list in a secure way.
0134: * The calling suite must have the com.sun.midp.ams permission "allowed".
0135: *
0136: * Should only be called in the AMS Isolate.
0137: *
0138: * @return MIDP MIDlet proxy list reference
0139: */
0140: public static MIDletProxyList getMIDletProxyList() {
0141: return getMIDletProxyList(null);
0142: }
0143:
0144: /**
0145: * Get a reference to the MIDlet proxy list in a secure way.
0146: * The calling suite must have the com.sun.midp.ams permission "allowed".
0147: *
0148: * Should only be called in the AMS Isolate.
0149: *
0150: * @param token SecurityToken with the AMS permission allowed or
0151: * null to use the midletSuite permission
0152: *
0153: * @return MIDP MIDlet proxy list reference
0154: */
0155: public static MIDletProxyList getMIDletProxyList(SecurityToken token) {
0156: if (token != null) {
0157: token.checkIfPermissionAllowed(Permissions.AMS);
0158: } else {
0159: MIDletSuite midletSuite = MIDletStateHandler
0160: .getMidletStateHandler().getMIDletSuite();
0161:
0162: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
0163: }
0164:
0165: return midletProxyList;
0166: }
0167:
0168: /**
0169: * Returns shutdown status
0170: *
0171: * @return true if shutdown is in progress, else false
0172: */
0173: static boolean shutdownInProgress() {
0174: return shutdownFlag;
0175: }
0176:
0177: /**
0178: * Package private constructor.
0179: * Shall be called from MIDletSuiteLoader's main()
0180: *
0181: * @param eventQueue reference to the event queue
0182: */
0183: MIDletProxyList(EventQueue eventQueue) {
0184: displayController = new DisplayController(this );
0185:
0186: /* register event listener for events processed by MIDletProxyList */
0187: new MIDletControllerEventListener(eventQueue, this );
0188: }
0189:
0190: /**
0191: * Enables the display controller to be replaced by an application
0192: * manager.
0193: *
0194: * @param newController new display controller
0195: */
0196: public void setDisplayController(DisplayController newController) {
0197: displayController = newController;
0198: }
0199:
0200: /**
0201: * Add a listener for MIDlet proxy list changes.
0202: *
0203: * @param listener MIDlet proxy list listener
0204: */
0205: public void addListener(MIDletProxyListListener listener) {
0206: listeners.addElement(listener);
0207: }
0208:
0209: /**
0210: * Remove a listener for MIDlet proxy list changes.
0211: *
0212: * @param listener MIDlet proxy list listener
0213: */
0214: public void removeListener(MIDletProxyListListener listener) {
0215: listeners.removeElement(listener);
0216: }
0217:
0218: /**
0219: * Get an enumeration of MIDlet proxies.
0220: *
0221: * @return enumeration of midletProxys
0222: */
0223: public Enumeration getMIDlets() {
0224: Vector v = new Vector();
0225: synchronized (midletProxies) {
0226: int size = midletProxies.size();
0227: for (int i = 0; i < size; i++) {
0228: v.addElement(midletProxies.elementAt(i));
0229: }
0230: }
0231: return v.elements();
0232: }
0233:
0234: /**
0235: * Shutdown the system by asynchronously destroying all MIDlets.
0236: *
0237: */
0238: public void shutdown() {
0239: synchronized (midletProxies) {
0240: if (shutdownFlag) {
0241: return;
0242: }
0243:
0244: shutdownFlag = true;
0245:
0246: if (midletProxies.size() == 0) {
0247: /*
0248: * We are done if no proxyies are in the list.
0249: * Notify any objects waiting for shutdown.
0250: */
0251: midletProxies.notifyAll();
0252: return;
0253: }
0254:
0255: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0256: MIDletProxy current = (MIDletProxy) midletProxies
0257: .elementAt(i);
0258:
0259: current.destroyMidlet();
0260: }
0261: }
0262: }
0263:
0264: /** Wait for the system to asynchronously destroy all MIDlets. */
0265: public void waitForShutdownToComplete() {
0266: synchronized (midletProxies) {
0267: // Wait for shutdown to be called.
0268: while (!shutdownFlag) {
0269: try {
0270: midletProxies.wait();
0271: } catch (InterruptedException ie) {
0272: return;
0273: }
0274: }
0275:
0276: // Wait for all MIDlets to be destroyed.
0277: while (midletProxies.size() > 0) {
0278: try {
0279: midletProxies.wait();
0280: } catch (InterruptedException ie) {
0281: return;
0282: }
0283: }
0284: }
0285: }
0286:
0287: /**
0288: * Find the MIDletProxy that has matching Isolate ID and Display ID.
0289: *
0290: * @param isolateId Isolate ID
0291: * @param displayId Display ID
0292: *
0293: * @return a reference to the matching MIDletProxy or null if no match
0294: */
0295: private MIDletProxy findMIDletProxy(int isolateId, int displayId) {
0296: synchronized (midletProxies) {
0297: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0298: MIDletProxy current = (MIDletProxy) midletProxies
0299: .elementAt(i);
0300:
0301: if (current.getIsolateId() == isolateId
0302: && current.getDisplayId() == displayId) {
0303: return current;
0304: }
0305: }
0306: }
0307:
0308: return null;
0309: }
0310:
0311: /**
0312: * Find the MIDletProxy that has matching suiteId and classname.
0313: *
0314: * @param suiteId the suiteId of the target application
0315: * @param classname classname of the MIDlet
0316: *
0317: * @return a reference to the matching MIDletProxy or null if no match
0318: */
0319: public MIDletProxy findMIDletProxy(int suiteId, String classname) {
0320: synchronized (midletProxies) {
0321: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0322: MIDletProxy current = (MIDletProxy) midletProxies
0323: .elementAt(i);
0324:
0325: if (current.getSuiteId() == suiteId
0326: && current.getClassName().equals(classname)) {
0327: return current;
0328: }
0329: }
0330: }
0331:
0332: return null;
0333: }
0334:
0335: /**
0336: * Find the MIDletProxy that has matching external app ID.
0337: *
0338: * @param externalAppId ID assigned by the external application manager
0339: *
0340: * @return a reference to the matching MIDletProxy or null if no match
0341: */
0342: public MIDletProxy findMIDletProxy(int externalAppId) {
0343: synchronized (midletProxies) {
0344: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0345: MIDletProxy current = (MIDletProxy) midletProxies
0346: .elementAt(i);
0347:
0348: if (current.getExternalAppId() == externalAppId) {
0349: return current;
0350: }
0351: }
0352: }
0353:
0354: return null;
0355: }
0356:
0357: /**
0358: * Retireves proxy whose peer application runs in the AMS isolate.
0359: * The proxy is identified by isolate ID since only one application
0360: * can run in the AMS solate.
0361: * @return the proxy or null if one cannot be found
0362: */
0363: public MIDletProxy findAmsProxy() {
0364: if (null == amsProxy) {
0365: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0366: MIDletProxy current = (MIDletProxy) midletProxies
0367: .elementAt(i);
0368:
0369: if (current.getIsolateId() == MIDletSuiteUtils
0370: .getAmsIsolateId()) {
0371: amsProxy = current;
0372: break;
0373: }
0374: }
0375: }
0376:
0377: return amsProxy;
0378: }
0379:
0380: /**
0381: * Process a MIDlet created notification.
0382: * MIDletControllerEventConsumer I/F method.
0383: *
0384: * @param midletSuiteId ID of the MIDlet suite
0385: * @param midletClassName Class name of the MIDlet
0386: * @param midletIsolateId isolate ID of the sending MIDlet
0387: * @param midletExternalAppId ID of given by an external application
0388: * manager
0389: * @param midletDisplayName name to show the user
0390: */
0391: public void handleMIDletCreateNotifyEvent(int midletSuiteId,
0392: String midletClassName, int midletIsolateId,
0393: int midletExternalAppId, String midletDisplayName) {
0394:
0395: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0396: midletClassName);
0397: if (midletProxy != null) {
0398: /**
0399: * The isolate this MIDlet was last run in, died because the
0400: * event proccessing encountered a fatal error, which ends
0401: * the isolate without notifing the proxy list.
0402: * So just remove the MIDlet's proxy now.
0403: * So we can add the new midlet proxy.
0404: */
0405: removeMidletProxy(midletProxy);
0406: }
0407:
0408: /* MIDlet's are constructed in PAUSED state. */
0409: midletProxy = new MIDletProxy(this , midletExternalAppId,
0410: midletIsolateId, midletSuiteId, midletClassName,
0411: midletDisplayName, MIDletProxy.MIDLET_PAUSED);
0412:
0413: int suspendResumeState = SuspendSystem.getInstance(
0414: classSecurityToken).getState();
0415:
0416: if ((suspendResumeState == SuspendSystem.SUSPENDED)
0417: || (suspendResumeState == SuspendSystem.SUSPENDING)) {
0418: MIDletProxyUtils.terminateMIDletIsolate(midletProxy, this );
0419: midletProxy = null;
0420: return;
0421: }
0422:
0423: midletProxies.addElement(midletProxy);
0424:
0425: notifyListenersOfProxyListChange(midletProxy, PROXY_ADDED);
0426:
0427: displayController.midletCreated(midletProxy);
0428: }
0429:
0430: /**
0431: * Process a MIDlet active notification
0432: * MIDletControllerEventConsumer I/F method.
0433: *
0434: * TBD: param midletProxy proxy with information about MIDlet
0435: *
0436: * @param midletSuiteId ID of the MIDlet suite
0437: * @param midletClassName Class name of the MIDlet
0438: */
0439: public void handleMIDletActiveNotifyEvent(int midletSuiteId,
0440: String midletClassName) {
0441:
0442: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0443: midletClassName);
0444: if (midletProxy == null) {
0445: /*
0446: * There is nothing we can do for the other events
0447: * if a proxy was not found.
0448: *
0449: * Sometimes an display can send an event after a
0450: * MIDlet's destroyApp method is called and the proxy removed
0451: * from this list. One of the cases is when
0452: * a thread the MIDlet started and is still running after
0453: * the destroyApp method has returned, calls display.setCurrent
0454: * with null while cleaning up.
0455: */
0456: return;
0457: }
0458:
0459: midletProxy.setMidletState(MIDletProxy.MIDLET_ACTIVE);
0460: notifyListenersOfProxyUpdate(midletProxy,
0461: MIDletProxyListListener.MIDLET_STATE);
0462: setForegroundMIDlet(displayController.midletActive(midletProxy));
0463: notifyIfMidletActive();
0464: }
0465:
0466: /**
0467: * Process a MIDlet paused notification.
0468: * MIDletControllerEventConsumer I/F method.
0469: *
0470: * TBD: param midletProxy proxy with information about MIDlet
0471: *
0472: * @param midletSuiteId ID of the MIDlet suite
0473: * @param midletClassName Class name of the MIDlet
0474: */
0475: public void handleMIDletPauseNotifyEvent(
0476: // MIDletProxy midletProxy) {
0477: int midletSuiteId, String midletClassName) {
0478:
0479: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0480: midletClassName);
0481: if (midletProxy == null) {
0482: /*
0483: * There is nothing we can do for the other events
0484: * if a proxy was not found. See midletActiveNotification().
0485: */
0486: return;
0487: }
0488:
0489: midletProxy.setMidletState(MIDletProxy.MIDLET_PAUSED);
0490: notifyListenersOfProxyUpdate(midletProxy,
0491: MIDletProxyListListener.MIDLET_STATE);
0492:
0493: setForegroundMIDlet(displayController.midletPaused(midletProxy));
0494: }
0495:
0496: /**
0497: * Process a MIDlet destroyed event.
0498: * MIDletControllerEventConsumer I/F method.
0499: *
0500: * TBD: param midletProxy proxy with information about MIDlet
0501: *
0502: * @param midletSuiteId ID of the MIDlet suite
0503: * @param midletClassName Class name of the MIDlet
0504: */
0505: public void handleMIDletDestroyNotifyEvent(
0506: // MIDletProxy midletProxy) {
0507: int midletSuiteId, String midletClassName) {
0508:
0509: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0510: midletClassName);
0511: if (midletProxy == null) {
0512: /*
0513: * There is nothing we can do for the event
0514: * if a proxy was not found. See midletActiveNotification().
0515: */
0516: return;
0517: }
0518:
0519: midletProxy.destroyedNotification();
0520: removeMidletProxy(midletProxy);
0521: }
0522:
0523: /**
0524: * Processes a MIDLET_RESUME_REQUEST event.
0525: *
0526: * MIDletControllerEventConsumer I/F method.
0527: *
0528: * @param midletSuiteId ID of the MIDlet suite
0529: * @param midletClassName Class name of the MIDlet
0530: */
0531: public void handleMIDletResumeRequestEvent(int midletSuiteId,
0532: String midletClassName) {
0533: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0534: midletClassName);
0535: if (midletProxy == null) {
0536: /*
0537: * There is nothing we can do for the event
0538: * if a proxy was not found. See midletActiveNotification().
0539: */
0540: return;
0541: }
0542:
0543: // Just grant the request.
0544: midletProxy.activateMidlet();
0545: }
0546:
0547: /**
0548: * Handles notification event of MIDlet resources pause.
0549: * MIDletControllerEventConsumer I/F method.
0550: *
0551: * @param midletSuiteId ID of the MIDlet suite
0552: * @param midletClassName Class name of the MIDlet
0553: */
0554: public void handleMIDletRsPauseNotifyEvent(int midletSuiteId,
0555: String midletClassName) {
0556:
0557: MIDletProxy midletProxy = findMIDletProxy(midletSuiteId,
0558: midletClassName);
0559: if (midletProxy == null) {
0560: /*
0561: * There is nothing we can do for the other events
0562: * if a proxy was not found.
0563: */
0564: return;
0565: }
0566:
0567: notifyListenersOfProxyUpdate(midletProxy,
0568: MIDletProxyListListener.RESOURCES_SUSPENDED);
0569: }
0570:
0571: /**
0572: * Process a MIDlet destroy request event.
0573: * MIDletControllerEventConsumer I/F method.
0574: *
0575: * TBD: param midletProxy proxy with information about MIDlet
0576: *
0577: * @param midletIsolateId isolate ID of the sending Display
0578: * @param midletDisplayId ID of the sending Display
0579: */
0580: public void handleMIDletDestroyRequestEvent(
0581: // MIDletProxy midletProxy) {
0582: int midletIsolateId, int midletDisplayId) {
0583:
0584: MIDletProxy midletProxy = findMIDletProxy(midletIsolateId,
0585: midletDisplayId);
0586: if (midletProxy == null) {
0587: return;
0588: }
0589:
0590: midletProxy.destroyMidlet();
0591: }
0592:
0593: /**
0594: * Process an ACTIVATE_ALL_EVENT.
0595: * MIDletControllerEventConsumer I/F method.
0596: *
0597: */
0598: public void handleActivateAllEvent() {
0599: SuspendSystem.getInstance(classSecurityToken).resume();
0600:
0601: synchronized (midletProxies) {
0602: MIDletProxy current;
0603:
0604: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0605: current = (MIDletProxy) midletProxies.elementAt(i);
0606:
0607: current.activateMidlet();
0608: }
0609: }
0610: }
0611:
0612: /**
0613: * Process a PAUSE_ALL_EVENT.
0614: * MIDletControllerEventConsumer I/F method.
0615: */
0616: public void handlePauseAllEvent() {
0617: synchronized (midletProxies) {
0618: MIDletProxy current;
0619:
0620: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0621: current = (MIDletProxy) midletProxies.elementAt(i);
0622: if (!current.wasNotActive) {
0623: SuspendSystem.getInstance(classSecurityToken)
0624: .addSuspendDependency(current);
0625: current.pauseMidlet();
0626: } else {
0627: MIDletProxyUtils.terminateMIDletIsolate(current,
0628: this );
0629: }
0630: }
0631: }
0632:
0633: SuspendSystem.getInstance(classSecurityToken).suspend();
0634:
0635: }
0636:
0637: /**
0638: * Finalizes PAUSE_ALL_EVENT processing after timeout for
0639: * pausing MIDlets expires.
0640: */
0641: public void terminatePauseAll() {
0642: synchronized (midletProxies) {
0643: MIDletProxy current;
0644:
0645: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0646: current = (MIDletProxy) midletProxies.elementAt(i);
0647:
0648: current.terminateNotPausedMidlet();
0649: }
0650:
0651: }
0652: }
0653:
0654: /**
0655: * Process a SHUTDOWN_ALL_EVENT.
0656: * MIDletControllerEventConsumer I/F method.
0657: *
0658: * It simply calls "shutdown()". In future it shall be merged with
0659: * "shutdown()" and substitute it.
0660: */
0661: public void handleDestroyAllEvent() {
0662: shutdown();
0663: }
0664:
0665: /**
0666: * Processes FATAL_ERROR_NOTIFICATION.
0667: *
0668: * MIDletControllerEventConsumer I/F method.
0669: *
0670: * @param midletIsolateId isolate ID of the sending isolate
0671: * @param midletDisplayId ID of the sending Display
0672: */
0673: public void handleFatalErrorNotifyEvent(int midletIsolateId,
0674: int midletDisplayId) {
0675:
0676: removeIsolateProxies(midletIsolateId);
0677: AmsUtil.terminateIsolate(midletIsolateId);
0678: }
0679:
0680: /**
0681: * Notifies the device if an active MIDlet appeared in the system.
0682: * The notification is produced only once when the system runs
0683: * out of the state with all the MIDlets being either paused
0684: * or destroyed.
0685: */
0686: private void notifyIfMidletActive() {
0687: MIDletProxy midletProxy;
0688:
0689: synchronized (midletProxies) {
0690: if (allPaused) {
0691: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0692: midletProxy = (MIDletProxy) midletProxies
0693: .elementAt(i);
0694: if (midletProxy.getMidletState() == MIDletProxy.MIDLET_ACTIVE) {
0695: allPaused = false;
0696: notifyResumeAll0();
0697: break;
0698: }
0699: }
0700: }
0701: }
0702: }
0703:
0704: /**
0705: * Notifies the device if all MIDlets considered to be paused, that is
0706: * at least one MIDlet is paused and others are either paused or
0707: * destroyed. The notification is produced only once when the system
0708: * runs to that state.
0709: */
0710: private void notifyIfAllPaused() {
0711: boolean allMidletsPaused = false;
0712: int midletState;
0713:
0714: synchronized (midletProxies) {
0715: if (!allPaused) {
0716: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0717: midletState = ((MIDletProxy) midletProxies
0718: .elementAt(i)).getMidletState();
0719:
0720: if (MIDletProxy.MIDLET_PAUSED == midletState) {
0721: allMidletsPaused = true;
0722: } else if (MIDletProxy.MIDLET_DESTROYED != midletState) {
0723: allMidletsPaused = false;
0724: break;
0725: }
0726: }
0727:
0728: if (allMidletsPaused) {
0729: allPaused = true;
0730: notifySuspendAll0();
0731: }
0732: }
0733: }
0734: }
0735:
0736: /**
0737: * Process a Display created notification.
0738: * MIDletControllerEventConsumer I/F method.
0739: *
0740: * @param midletIsolateId isolate ID of the sending Display
0741: * @param midletDisplayId ID of the sending Display
0742: * @param midletClassName Class name of the MIDlet that owns the display
0743: */
0744: public void handleDisplayCreateNotifyEvent(int midletIsolateId,
0745: int midletDisplayId, String midletClassName) {
0746:
0747: MIDletProxy midletProxy = null;
0748:
0749: synchronized (midletProxies) {
0750: for (int i = midletProxies.size() - 1; i >= 0; i--) {
0751: MIDletProxy current = (MIDletProxy) midletProxies
0752: .elementAt(i);
0753: if (current.getIsolateId() == midletIsolateId
0754: && current.getClassName().equals(
0755: midletClassName)) {
0756: midletProxy = current;
0757: break;
0758: }
0759: }
0760: }
0761:
0762: if (midletProxy == null) {
0763: /**
0764: * The isolate is create a display without a MIDlet to display
0765: * a fatal error loading the suite in SVM mode.
0766: * So just do nothing, a preempt event will follow.
0767: */
0768: return;
0769: }
0770:
0771: /* Just set the display ID of the proxy. */
0772: midletProxy.setDisplayId(midletDisplayId);
0773: }
0774:
0775: /**
0776: * Process a foreground request event.
0777: * MIDletControllerEventConsumer I/F method.
0778: *
0779: * TBD: param midletProxy proxy with information about MIDlet
0780: *
0781: * @param midletIsolateId isolate ID of the sending Display
0782: * @param midletDisplayId ID of the sending Display
0783: * @param isAlert true if the current displayable is an Alert
0784: */
0785: public void handleDisplayForegroundRequestEvent(
0786: // MIDletProxy midletProxy) {
0787: int midletIsolateId, int midletDisplayId, boolean isAlert) {
0788:
0789: MIDletProxy midletProxy = findMIDletProxy(midletIsolateId,
0790: midletDisplayId);
0791: if (midletProxy == null) {
0792: /*
0793: * There is nothing we can do for the event
0794: * if a proxy was not found. See midletActiveNotification().
0795: */
0796: return;
0797: }
0798:
0799: if (midletProxy == foregroundMidlet) {
0800: // force alert waiting to false, since it can't be waiting
0801: midletProxy.setWantsForeground(true, false);
0802: } else {
0803: midletProxy.setWantsForeground(true, isAlert);
0804: setForegroundMIDlet(displayController
0805: .foregroundRequest(midletProxy));
0806: }
0807:
0808: /**
0809: * The internal calls to notifyListenersOfProxyChange() within
0810: * setForegroundMIDlet() should not override the behaviour of
0811: * listener which is an IndicatorManager in this case. So,
0812: * notifyListenersOfProxyChange() should be called after
0813: * setForegroundMIDlet().
0814: */
0815: notifyListenersOfProxyUpdate(midletProxy,
0816: MIDletProxyListListener.WANTS_FOREGROUND);
0817: }
0818:
0819: /**
0820: * Process a background request event.
0821: * MIDletControllerEventConsumer I/F method.
0822: *
0823: * TBD: param midletProxy proxy with information about MIDlet
0824: *
0825: * @param midletIsolateId isolate ID of the sending Display
0826: * @param midletDisplayId ID of the sending Display
0827: */
0828: public void handleDisplayBackgroundRequestEvent(
0829: // MIDletProxy midletProxy) {
0830: int midletIsolateId, int midletDisplayId) {
0831:
0832: MIDletProxy midletProxy = findMIDletProxy(midletIsolateId,
0833: midletDisplayId);
0834: if (midletProxy == null) {
0835: /*
0836: * There is nothing we can do for the event
0837: * if a proxy was not found.
0838: *
0839: * Sometimes an display can send an event before
0840: * MIDlet. One of the cases is when
0841: * a MIDlet calls Display.setCurrent with a new displayable in
0842: * its constructor which happens before the MIDlet created
0843: * event.
0844: *
0845: * Sometimes an display can send an event after a
0846: * MIDlet's destroyApp method is called and the proxy removed
0847: * from this list. One of the cases is when
0848: * a thread the MIDlet started and is still running after
0849: * the destroyApp method has returned, calls display.setCurrent
0850: * with null while cleaning up.
0851: */
0852: return;
0853: }
0854:
0855: midletProxy.setWantsForeground(false, false);
0856: setForegroundMIDlet(displayController
0857: .backgroundRequest(midletProxy));
0858: notifyListenersOfProxyUpdate(midletProxy,
0859: MIDletProxyListListener.WANTS_FOREGROUND);
0860: }
0861:
0862: /**
0863: * Process a "display preempt start" event.
0864: * <p>
0865: * Set the foreground to a given display if a certain display
0866: * has the foreground. Used to start preempting.
0867: *
0868: * MIDletControllerEventConsumer I/F method.
0869: *
0870: * @param midletIsolateId isolate ID of the sending Display
0871: * @param midletDisplayId ID of the sending Display
0872: */
0873: public void handleDisplayPreemptStartEvent(int midletIsolateId,
0874: int midletDisplayId) {
0875:
0876: MIDletProxy preempting = new MIDletProxy(this , 0,
0877: midletIsolateId, MIDletSuite.UNUSED_SUITE_ID, null,
0878: null, MIDletProxy.MIDLET_ACTIVE);
0879: preempting.setDisplayId(midletDisplayId);
0880:
0881: MIDletProxy nextForeground = displayController
0882: .startPreempting(preempting);
0883:
0884: if (nextForeground != null) {
0885: setForegroundMIDlet(nextForeground);
0886: }
0887: }
0888:
0889: /**
0890: * Process a "display preempt stop" event.
0891: * <p>
0892: * Set the foreground to a given display if a certain display
0893: * has the foreground. Used to end preempting.
0894: *
0895: * MIDletControllerEventConsumer I/F method.
0896: *
0897: * @param midletIsolateId isolate ID of the sending Display
0898: * @param midletDisplayId ID of the sending Display
0899: */
0900: public void handleDisplayPreemptStopEvent(int midletIsolateId,
0901: int midletDisplayId) {
0902:
0903: MIDletProxy nextForeground = displayController.endPreempting(
0904: midletIsolateId, midletDisplayId);
0905:
0906: if (nextForeground != null) {
0907: setForegroundMIDlet(nextForeground);
0908: }
0909: }
0910:
0911: /**
0912: * Process a select foreground event by putting the foreground selector
0913: * MIDlet in the foreground.
0914: *
0915: * MIDletControllerEventConsumer I/F method.
0916: *
0917: */
0918: public void handleMIDletForegroundSelectEvent(int onlyFromLaunched) {
0919: MIDletProxy nextForeground = displayController
0920: .selectForeground(onlyFromLaunched == 1);
0921:
0922: if (nextForeground == foregroundMidlet) {
0923: return;
0924: }
0925:
0926: setForegroundMIDlet(nextForeground);
0927: }
0928:
0929: /**
0930: * Process an event to transition the foreground from a current display
0931: * to a target MIDlet by ID and classname. If the source display
0932: * does not currently own the foreground the request is ignored.
0933: * If the target MIDlet is found in the active list then it it set
0934: * as the foreground. If not found, then it should be added as
0935: * the next display to get the foreground (when it asks).
0936: *
0937: * MIDletControllerEventConsumer I/F method.
0938: *
0939: * @param originMIDletSuiteId ID of MIDlet from which
0940: * to take forefround ownership away,
0941: * @param originMIDletClassName Name of MIDlet from which
0942: * to take forefround ownership away
0943: * @param targetMIDletSuiteId ID of MIDlet
0944: * to give forefround ownership to,
0945: * @param targetMIDletClassName Name of MIDlet
0946: * to give forefround ownership to
0947: */
0948: public void handleMIDletForegroundTransferEvent(
0949: int originMIDletSuiteId, String originMIDletClassName,
0950: int targetMIDletSuiteId, String targetMIDletClassName) {
0951:
0952: MIDletProxy origin = findMIDletProxy(originMIDletSuiteId,
0953: originMIDletClassName);
0954: if (origin == null) {
0955: return;
0956: }
0957: // See if the foreground can be handed to the target MIDlet
0958: MIDletProxy target = findMIDletProxy(targetMIDletSuiteId,
0959: targetMIDletClassName);
0960: if (target != null) {
0961: target.setWantsForeground(true, false);
0962: // Let the DisplayController make the UE policy choice
0963: setForegroundMIDlet(displayController.transferRequest(
0964: origin, target));
0965:
0966: /**
0967: * The internal calls to notifyListenersOfProxyChange() within
0968: * setForegroundMIDlet() should not override the behaviour of a
0969: * listener which is an IndicatorManager in this case. So,
0970: * notifyListenersOfProxyChange() should be called after
0971: * setForegroundMIDlet().
0972: */
0973: notifyListenersOfProxyUpdate(target,
0974: MIDletProxyListListener.WANTS_FOREGROUND);
0975: }
0976: }
0977:
0978: /**
0979: * Processes SET_FOREGROUND_BY_NAME_REQUEST event.
0980: * <p>
0981: * Set specified MIDlet to foreground.
0982: *
0983: * @param suiteId MIDlet's suite ID
0984: * @param className MIDlet's class name
0985: */
0986: public void handleSetForegroundByNameRequestEvent(int suiteId,
0987: String className) {
0988:
0989: MIDletProxy midletProxy = findMIDletProxy(suiteId, className);
0990: if (midletProxy != null) {
0991: setForegroundMIDlet(midletProxy);
0992: }
0993: }
0994:
0995: /**
0996: * Process a MIDlet start error event.
0997: * Notify from last to first added to allow the listener to
0998: * remove itself without causing a missed notification.
0999: *
1000: * MIDletControllerEventConsumer I/F method.
1001: *
1002: * @param midletSuiteId ID of the MIDlet suite
1003: * @param midletClassName Class name of the MIDlet
1004: * @param midletExternalAppId ID of given by an external application
1005: * manager
1006: * @param errorCode start error code
1007: * @param errorDetails start error details
1008: */
1009: public void handleMIDletStartErrorEvent(int midletSuiteId,
1010: String midletClassName, int midletExternalAppId,
1011: int errorCode, String errorDetails) {
1012:
1013: for (int i = listeners.size() - 1; i >= 0; i--) {
1014: MIDletProxyListListener listener = (MIDletProxyListListener) listeners
1015: .elementAt(i);
1016:
1017: listener.midletStartError(midletExternalAppId,
1018: midletSuiteId, midletClassName, errorCode,
1019: errorDetails);
1020: }
1021: }
1022:
1023: /**
1024: * Sets the foreground MIDlet. If the given midletProxy is paused,
1025: * then it will be activated before given the foreground.
1026: * the internal system property "pause_app_in_background" is true,
1027: * then previous foreground MIDlet will be paused.
1028: * <p>
1029: * The follow steps are performed when changed:<p>
1030: * 1. Send an event to notify the old foreground Display it has lost the
1031: * foreground<p>
1032: * 2. Change the foreground field in this object and in the native
1033: * code. <p>
1034: * 3. Send an event to notify the new foreground Display is has gained the
1035: * foreground<p>
1036: *
1037: * @param newForeground Proxy of the MIDlet to be put in the foreground
1038: */
1039: public void setForegroundMIDlet(MIDletProxy newForeground) {
1040: if (newForeground != null
1041: && (newForeground.getMidletState() == MIDletProxy.MIDLET_DESTROYED
1042: || newForeground == foregroundMidlet || newForeground
1043: .noDisplay())) {
1044: return;
1045: }
1046:
1047: if (foregroundMidlet != null
1048: && (foregroundMidlet.getMidletState() != MIDletProxy.MIDLET_DESTROYED)) {
1049: /*
1050: * Background MIDlet will run with a lower priority
1051: */
1052: MIDletProxyUtils.minPriority(foregroundMidlet);
1053: foregroundMidlet.notifyMIDletHasForeground(false);
1054: }
1055:
1056: foregroundMidlet = displayController
1057: .foregroundMidletChanging(newForeground);
1058:
1059: /*
1060: * When there are no more midletProxys the foreground midletProxy
1061: * will be null again.
1062: */
1063:
1064: if (foregroundMidlet != null) {
1065: setForegroundInNativeState(foregroundMidlet.getIsolateId(),
1066: foregroundMidlet.getDisplayId());
1067: // This call with a true parameter will set the alertWaiting field.
1068: foregroundMidlet.notifyMIDletHasForeground(true);
1069:
1070: /*
1071: * Foreground MIDlet will run with a normal priority
1072: */
1073: MIDletProxyUtils.normalPriority(foregroundMidlet);
1074:
1075: notifyListenersOfProxyUpdate(foregroundMidlet,
1076: MIDletProxyListListener.ALERT_WAITING);
1077: } else {
1078: setForegroundInNativeState(MIDletSuiteUtils
1079: .getAmsIsolateId(), -1);
1080: }
1081: }
1082:
1083: /**
1084: * Get the foreground MIDlet.
1085: *
1086: * @return proxy to the MIDlet that is in the foreground
1087: */
1088: public MIDletProxy getForegroundMIDlet() {
1089: return foregroundMidlet;
1090: }
1091:
1092: /**
1093: * Return true if home indicator needs to be turned on
1094: *
1095: * @return true if any MIDlet has set an Alert as the current displayable
1096: * while in the background, otherwise false
1097: *
1098: */
1099: public boolean isAlertWaitingInBackground() {
1100: synchronized (midletProxies) {
1101: for (int i = midletProxies.size() - 1; i >= 0; i--) {
1102: MIDletProxy current = (MIDletProxy) midletProxies
1103: .elementAt(i);
1104:
1105: if (current.isAlertWaiting()) {
1106: return true;
1107: }
1108: }
1109: }
1110:
1111: return false;
1112: }
1113:
1114: /**
1115: * Check to see if the MIDlet is already started.
1116: *
1117: * @param id Suite ID of the MIDlet
1118: * @param className Class name of the MIDlet
1119: *
1120: * @return true if the MIDlet has been started
1121: */
1122: public boolean isMidletInList(int id, String className) {
1123: synchronized (midletProxies) {
1124: for (int i = midletProxies.size() - 1; i >= 0; i--) {
1125: MIDletProxy current = (MIDletProxy) midletProxies
1126: .elementAt(i);
1127:
1128: if (current.getSuiteId() == id
1129: && current.getClassName().equals(className)) {
1130: return true;
1131: }
1132: }
1133: }
1134:
1135: return false;
1136: }
1137:
1138: /**
1139: * Notify the listeners of change in the size of the proxy list.
1140: *
1141: * Notify from last to first added to allow the listener to
1142: * remove itself without causing a missed notification.
1143: *
1144: * @param midletProxy midletProxy that was added or removed in the list
1145: * @param notificationType type of change, added or removed
1146: */
1147: void notifyListenersOfProxyListChange(MIDletProxy midletProxy,
1148: int notificationType) {
1149:
1150: for (int i = listeners.size() - 1; i >= 0; i--) {
1151: MIDletProxyListListener listener = (MIDletProxyListListener) listeners
1152: .elementAt(i);
1153:
1154: switch (notificationType) {
1155: case PROXY_ADDED:
1156: listener.midletAdded(midletProxy);
1157: break;
1158:
1159: case PROXY_REMOVED:
1160: listener.midletRemoved(midletProxy);
1161: break;
1162: }
1163: }
1164: }
1165:
1166: /**
1167: * Notify the listeners of the midletProxy list that a proxy
1168: * has been updated.
1169: *
1170: * Notify from last to first added to allow the listener to
1171: * remove itself without causing a missed notification.
1172: *
1173: * @param midletProxy midletProxy that changed in the list
1174: * @param reason reason for the change
1175: */
1176: void notifyListenersOfProxyUpdate(MIDletProxy midletProxy,
1177: int reason) {
1178:
1179: for (int i = listeners.size() - 1; i >= 0; i--) {
1180: MIDletProxyListListener listener = (MIDletProxyListListener) listeners
1181: .elementAt(i);
1182:
1183: listener.midletUpdated(midletProxy, reason);
1184: }
1185: }
1186:
1187: /**
1188: * Removes a MidletProxy from the MidletProxyList
1189: *
1190: * @param midletProxy the MIDletProxy to be removed.
1191: */
1192: void removeMidletProxy(MIDletProxy midletProxy) {
1193: MIDletProxy preempting;
1194:
1195: /*
1196: * Remove the proxy before notifying the display controller,
1197: * so that new foreground search will not find MIDlet, but
1198: * don't notify the listener until after new foreground, since
1199: * the old foreground will generate a update notification.
1200: */
1201: midletProxies.removeElement(midletProxy);
1202:
1203: preempting = midletProxy.getPreemptingDisplay();
1204: if (preempting != null) {
1205: setForegroundMIDlet(displayController
1206: .midletDestroyed(preempting));
1207: } else {
1208: setForegroundMIDlet(displayController
1209: .midletDestroyed(midletProxy));
1210: }
1211:
1212: notifyListenersOfProxyListChange(midletProxy, PROXY_REMOVED);
1213:
1214: // An object may be waiting for the shutdown to complete
1215: if (shutdownFlag) {
1216: synchronized (midletProxies) {
1217: if (midletProxies.size() == 0) {
1218: midletProxies.notifyAll();
1219: }
1220: }
1221: }
1222: }
1223:
1224: /**
1225: * Removes the MIDletproxies that belong to the isolate id
1226: *
1227: * @param id IsolateId
1228: */
1229: void removeIsolateProxies(int id) {
1230: // We are removing multiple items from the list we
1231: // have to remove from the enumeration.
1232: Enumeration e = getMIDlets();
1233: while (e.hasMoreElements()) {
1234: MIDletProxy mp = (MIDletProxy) e.nextElement();
1235: if (mp.getIsolateId() == id) {
1236: removeMidletProxy(mp);
1237: }
1238: }
1239: }
1240:
1241: /**
1242: * Called to notify that java side of MIDP system has been suspended.
1243: */
1244: public void midpSuspended() {
1245: notifyIfAllPaused();
1246: }
1247:
1248: /**
1249: * Called to notify that java side of MIDP system has been resumed.
1250: */
1251: public void midpResumed() {
1252: }
1253:
1254: /**
1255: * Set foreground midletProxy in the native midletProxy list state.
1256: *
1257: * @param isolateId Isolate ID
1258: * @param displayId Display ID
1259: */
1260: private native void setForegroundInNativeState(int isolateId,
1261: int displayId);
1262:
1263: /**
1264: * Notify native code that all MIDlets have been paused.
1265: */
1266: private native void notifySuspendAll0();
1267:
1268: /**
1269: * Notify native code that an active MIDlet appeared in the system.
1270: */
1271: private native void notifyResumeAll0();
1272: }
|