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.installer;
0028:
0029: import java.io.*;
0030:
0031: import javax.microedition.io.*;
0032:
0033: import javax.microedition.lcdui.*;
0034:
0035: import javax.microedition.midlet.*;
0036:
0037: import javax.microedition.rms.*;
0038:
0039: import com.sun.midp.io.j2me.storage.*;
0040:
0041: import com.sun.midp.i18n.Resource;
0042:
0043: import com.sun.midp.i18n.ResourceConstants;
0044:
0045: import com.sun.midp.configurator.Constants;
0046:
0047: import com.sun.midp.main.TrustedMIDletIcon;
0048:
0049: import com.sun.midp.midlet.*;
0050:
0051: import com.sun.midp.midletsuite.*;
0052:
0053: import com.sun.midp.security.*;
0054:
0055: import com.sun.midp.content.CHManager;
0056:
0057: import com.sun.midp.log.Logging;
0058: import com.sun.midp.log.LogChannels;
0059: import com.sun.midp.io.j2me.storage.File;
0060:
0061: /**
0062: * The Graphical MIDlet suite installer.
0063: * <p>
0064: * The graphical installer is implements the installer requirements of the
0065: * MIDP OTA specification.</p>
0066: * <p>
0067: * If the Content Handler API (CHAPI) is present the GraphicalInstaller will
0068: * dequeue a single Invocation and install from the URL contained
0069: * in the request. If there is no Invocation present then the arguments below
0070: * will be used.
0071: * <p>
0072: * The MIDlet uses certain application properties as arguments: </p>
0073: * <ol>
0074: * <li>arg-0: "U" for update "I" or anything else for install</li>
0075: * <li>arg-1: Suite ID for updating, URL for installing
0076: * <li>arg-2: For installing a name to put in the title bar when installing
0077: * </ol>
0078: * @see CHManagerImpl
0079: * @see CHManager
0080: */
0081: public class GraphicalInstaller extends MIDlet implements
0082: CommandListener {
0083:
0084: /** Standard timeout for alerts. */
0085: public static final int ALERT_TIMEOUT = 1250;
0086: /** settings database */
0087: public static final String SETTINGS_STORE = "settings";
0088: /** record id of selected midlet */
0089: public static final int URL_RECORD_ID = 1;
0090: /** record is of the last installed midlet */
0091: public static final int SELECTED_MIDLET_RECORD_ID = 2;
0092:
0093: /** The installer that is being used to install or update a suite. */
0094: private Installer installer;
0095: /** Display for this MIDlet. */
0096: private Display display;
0097: /** Form obtain a password and a username. */
0098: private Form passwordForm;
0099: /** Contains the username for installing. */
0100: private TextField usernameField;
0101: /** Contains the password for installing. */
0102: private TextField passwordField;
0103: /** Background installer that holds state for the current install. */
0104: private BackgroundInstaller backgroundInstaller;
0105: /** Displays the progress of the install. */
0106: private Form progressForm;
0107: /** Gauge for progress form index. */
0108: private int progressGaugeIndex;
0109: /** URL for progress form index. */
0110: private int progressUrlIndex;
0111: /** Keeps track of when the display last changed, in milliseconds. */
0112: private long lastDisplayChange;
0113: /** What to display to the user when the current action is cancelled. */
0114: private String cancelledMessage;
0115: /** What to display to the user when the current action is finishing. */
0116: private String finishingMessage;
0117: /** ID of the storage where the new midlet suite will be installed. */
0118: private int storageId = Constants.INTERNAL_STORAGE_ID;
0119:
0120: /** Content handler specific install functions. */
0121: CHManager chmanager;
0122:
0123: /** Command object for "Stop" command for progress form. */
0124: private Command stopCmd = new Command(Resource
0125: .getString(ResourceConstants.STOP), Command.STOP, 1);
0126:
0127: /** Command object for "Cancel" command for the confirm form. */
0128: private Command cancelCmd = new Command(Resource
0129: .getString(ResourceConstants.CANCEL), Command.CANCEL, 1);
0130: /** Command object for "Install" command for the confirm download form. */
0131: private Command continueCmd = new Command(Resource
0132: .getString(ResourceConstants.INSTALL), Command.OK, 1);
0133: /** Command object for "Next" command for password form. */
0134: private Command nextCmd = new Command(Resource
0135: .getString(ResourceConstants.NEXT), Command.OK, 1);
0136: /** Command object for "continue" command for warning form. */
0137: private Command okCmd = new Command(Resource
0138: .getString(ResourceConstants.CONTINUE), Command.OK, 1);
0139: /** Command object for "OK" command for exception form. */
0140: private Command exceptionCmd = new Command(Resource
0141: .getString(ResourceConstants.OK), Command.OK, 1);
0142: /** Command object for "Yes" command for keep RMS form. */
0143: private Command keepRMSCmd = new Command(Resource
0144: .getString(ResourceConstants.YES), Command.OK, 1);
0145: /** Command object for "No" command for keep RMS form. */
0146: private Command removeRMSCmd = new Command(Resource
0147: .getString(ResourceConstants.NO), Command.CANCEL, 1);
0148:
0149: /**
0150: * Read image data from storage file to byte array.
0151: *
0152: * @param imageFileName name of the file with icon data
0153: * @return byte array with icon data, or null if file not found
0154: */
0155: private static byte[] getImageFileBytes(String imageFileName) {
0156: byte[] imageBytes;
0157: RandomAccessStream stream;
0158: stream = new RandomAccessStream();
0159: try {
0160: stream.connect(imageFileName, Connector.READ);
0161: imageBytes = new byte[stream.getSizeOf()];
0162: stream.readBytes(imageBytes, 0, imageBytes.length);
0163: stream.disconnect();
0164: return imageBytes;
0165: } catch (java.io.IOException noIcon) {
0166: }
0167: return null;
0168: }
0169:
0170: /**
0171: * Gets an image from the internal storage.
0172: *
0173: * IMPL_NOTE: this method should be moved somewhere.
0174: *
0175: * @param imageName image file name without a path and extension
0176: * @return Image loaded from storage, or null if not found
0177: */
0178: public static Image getImageFromInternalStorage(String imageName) {
0179: String imageFileName;
0180: byte[] imageBytes;
0181:
0182: MIDletStateHandler midletStateHandler = MIDletStateHandler
0183: .getMidletStateHandler();
0184: MIDletSuite midletSuite = midletStateHandler.getMIDletSuite();
0185: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
0186:
0187: imageFileName = File
0188: .getStorageRoot(Constants.INTERNAL_STORAGE_ID)
0189: + imageName;
0190: imageBytes = getImageFileBytes(imageFileName + ".raw");
0191: if (imageBytes == null) {
0192: imageBytes = getImageFileBytes(imageFileName + ".png");
0193: }
0194: if (imageBytes != null) {
0195: return Image.createImage(imageBytes, 0, imageBytes.length);
0196: }
0197: return null;
0198: }
0199:
0200: /**
0201: * Translate an InvalidJadException into a message for the user.
0202: *
0203: * @param exception exception to translate
0204: * @param name name of the MIDlet suite to insert into the message
0205: * @param vendor vendor of the MIDlet suite to insert into the message,
0206: * can be null
0207: * @param version version of the MIDlet suite to insert into the message,
0208: * can be null
0209: * @param jadUrl URL of a JAD, can be null
0210: *
0211: * @return message to display to the user
0212: */
0213: private static String translateJadException(
0214: InvalidJadException exception, String name, String vendor,
0215: String version, String jadUrl) {
0216: String[] values = { name, vendor, version, jadUrl,
0217: exception.getExtraData() };
0218: int key;
0219:
0220: switch (exception.getReason()) {
0221: case InvalidJadException.OLD_VERSION:
0222: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_OLD_VERSION;
0223: break;
0224:
0225: case InvalidJadException.ALREADY_INSTALLED:
0226: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_ALREADY_INSTALLED;
0227: break;
0228:
0229: case InvalidJadException.NEW_VERSION:
0230: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_NEW_VERSION;
0231: break;
0232:
0233: case InvalidJadException.JAD_SERVER_NOT_FOUND:
0234: case InvalidJadException.JAD_NOT_FOUND:
0235: case InvalidJadException.INVALID_JAD_URL:
0236: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_JAD_URL;
0237: break;
0238:
0239: case InvalidJadException.INVALID_JAD_TYPE:
0240: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_JAD_TYPE;
0241: break;
0242:
0243: case InvalidJadException.MISSING_PROVIDER_CERT:
0244: case InvalidJadException.MISSING_SUITE_NAME:
0245: case InvalidJadException.MISSING_VENDOR:
0246: case InvalidJadException.MISSING_VERSION:
0247: case InvalidJadException.MISSING_JAR_URL:
0248: case InvalidJadException.MISSING_JAR_SIZE:
0249: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_MISSING_JAD_INFO;
0250: break;
0251:
0252: case InvalidJadException.MISSING_CONFIGURATION:
0253: case InvalidJadException.MISSING_PROFILE:
0254: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_MISSING_JAR_INFO;
0255: break;
0256:
0257: case InvalidJadException.INVALID_KEY:
0258: case InvalidJadException.INVALID_VALUE:
0259: case InvalidJadException.INVALID_VERSION:
0260: case InvalidJadException.PUSH_FORMAT_FAILURE:
0261: case InvalidJadException.PUSH_CLASS_FAILURE:
0262: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_FORMAT;
0263: break;
0264:
0265: case InvalidJadException.DEVICE_INCOMPATIBLE:
0266: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_DEVICE_INCOMPATIBLE;
0267: break;
0268:
0269: case InvalidJadException.JAD_MOVED:
0270: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_JAD_MOVED;
0271: break;
0272:
0273: case InvalidJadException.INSUFFICIENT_STORAGE:
0274: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INSUFFICIENT_STORAGE;
0275: break;
0276:
0277: case InvalidJadException.JAR_SERVER_NOT_FOUND:
0278: case InvalidJadException.JAR_NOT_FOUND:
0279: case InvalidJadException.INVALID_JAR_URL:
0280: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_JAR_NOT_FOUND;
0281: break;
0282:
0283: case InvalidJadException.INVALID_JAR_TYPE:
0284: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_JAR_TYPE;
0285: break;
0286:
0287: case InvalidJadException.SUITE_NAME_MISMATCH:
0288: case InvalidJadException.VERSION_MISMATCH:
0289: case InvalidJadException.VENDOR_MISMATCH:
0290: case InvalidJadException.JAR_SIZE_MISMATCH:
0291: case InvalidJadException.ATTRIBUTE_MISMATCH:
0292: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_ATTRIBUTE_MISMATCH;
0293: break;
0294:
0295: case InvalidJadException.CORRUPT_JAR:
0296: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_CORRUPT_JAR;
0297: break;
0298:
0299: case InvalidJadException.CANNOT_AUTH:
0300: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_CANNOT_AUTH;
0301: break;
0302:
0303: case InvalidJadException.CORRUPT_PROVIDER_CERT:
0304: case InvalidJadException.INVALID_PROVIDER_CERT:
0305: case InvalidJadException.CORRUPT_SIGNATURE:
0306: case InvalidJadException.INVALID_SIGNATURE:
0307: case InvalidJadException.UNSUPPORTED_CERT:
0308: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_SIGNATURE;
0309: break;
0310:
0311: case InvalidJadException.UNKNOWN_CA:
0312: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_UNKNOWN_CA;
0313: break;
0314:
0315: case InvalidJadException.EXPIRED_PROVIDER_CERT:
0316: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_EXPIRED_PROVIDER_CERT;
0317: break;
0318:
0319: case InvalidJadException.EXPIRED_CA_KEY:
0320: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_EXPIRED_CA_KEY;
0321: break;
0322:
0323: case InvalidJadException.AUTHORIZATION_FAILURE:
0324: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_AUTHORIZATION_FAILURE;
0325: break;
0326:
0327: case InvalidJadException.CA_DISABLED:
0328: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_CA_DISABLED;
0329: break;
0330:
0331: case InvalidJadException.PUSH_DUP_FAILURE:
0332: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_PUSH_DUP_FAILURE;
0333: break;
0334:
0335: case InvalidJadException.PUSH_PROTO_FAILURE:
0336: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_PUSH_PROTO_FAILURE;
0337: break;
0338:
0339: case InvalidJadException.TRUSTED_OVERWRITE_FAILURE:
0340: if (exception.getExtraData() != null) {
0341: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_TRUSTED_OVERWRITE_FAILURE;
0342: } else {
0343: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_TRUSTED_OVERWRITE_FAILURE_2;
0344: }
0345:
0346: break;
0347:
0348: case InvalidJadException.TOO_MANY_PROPS:
0349: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_APP_TOO_BIG;
0350: break;
0351:
0352: case InvalidJadException.INVALID_CONTENT_HANDLER:
0353: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_INVALID_CONTENT_HANDLER;
0354: break;
0355:
0356: case InvalidJadException.CONTENT_HANDLER_CONFLICT:
0357: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_CONTENT_HANDLER_CONFLICT;
0358: break;
0359:
0360: case InvalidJadException.JAR_CLASSES_VERIFICATION_FAILED:
0361: // This constant is shared between graphical installer
0362: // and standalone class verifier MIDlet used for SVM mode
0363: key = ResourceConstants.AMS_CLASS_VERIFIER_FAILURE;
0364: break;
0365:
0366: case InvalidJadException.UNSUPPORTED_CHAR_ENCODING:
0367: key = ResourceConstants.AMS_GRA_INTLR_INVALIDJADEXCEPTION_UNSUPPORTED_CHAR_ENCODING;
0368: break;
0369:
0370: default:
0371: return exception.getMessage();
0372: }
0373:
0374: return Resource.getString(key, values);
0375: }
0376:
0377: /**
0378: * Create and initialize a new graphical installer MIDlet.
0379: * <p>
0380: * If a ContentHandler request to install a suite is found,
0381: * then that URL will be installed. In this case the command
0382: * arguments are ignored.
0383: * <p>
0384: * The Display is retrieved and the list of MIDlet will be retrieved or
0385: * update a currently installed suite.
0386: */
0387: public GraphicalInstaller() {
0388: int suiteId;
0389: String arg0;
0390: String label;
0391: String url;
0392:
0393: installer = new HttpInstaller();
0394: display = Display.getDisplay(this );
0395:
0396: initSettings();
0397:
0398: // Establish Content handler installer context
0399: chmanager = CHManager.getManager(null);
0400:
0401: // Get the URL, if any, provided from the invocation mechanism.
0402: url = chmanager.getInstallURL(this );
0403: if (url != null) {
0404: label = Resource.getString(ResourceConstants.APPLICATION);
0405: installSuite(label, url);
0406: return;
0407: }
0408:
0409: arg0 = getAppProperty("arg-0");
0410: if (arg0 == null) {
0411: // goto back to the discovery midlet
0412: exit(false);
0413: return;
0414: }
0415:
0416: if ("U".equals(arg0)) {
0417: String strSuiteID = getAppProperty("arg-1");
0418: suiteId = MIDletSuite.UNUSED_SUITE_ID;
0419:
0420: if (strSuiteID != null) {
0421: try {
0422: suiteId = Integer.parseInt(strSuiteID);
0423: } catch (NumberFormatException nfe) {
0424: // Intentionally ignored
0425: }
0426: }
0427:
0428: if (suiteId == MIDletSuite.UNUSED_SUITE_ID) {
0429: // goto back to the discovery midlet
0430: exit(false);
0431: return;
0432: }
0433:
0434: updateSuite(suiteId);
0435: return;
0436: }
0437:
0438: url = getAppProperty("arg-1");
0439: if (url == null) {
0440: // goto back to the discovery midlet
0441: exit(false);
0442: return;
0443: }
0444:
0445: label = getAppProperty("arg-2");
0446: if (label == null || label.length() == 0) {
0447: label = Resource.getString(ResourceConstants.APPLICATION);
0448: }
0449:
0450: installSuite(label, url);
0451: }
0452:
0453: /**
0454: * Start.
0455: */
0456: public void startApp() {
0457: }
0458:
0459: /**
0460: * Pause; there are no resources that need to be released.
0461: */
0462: public void pauseApp() {
0463: }
0464:
0465: /**
0466: * Destroy cleans up.
0467: *
0468: * @param unconditional is ignored; this object always
0469: * destroys itself when requested.
0470: */
0471: public void destroyApp(boolean unconditional) {
0472: if (installer != null) {
0473: installer.stopInstalling();
0474: }
0475:
0476: /* The backgroundInstaller could be waiting for the user. */
0477: cancelBackgroundInstall();
0478: }
0479:
0480: /**
0481: * Exit the GraphicalInstaller with the status supplied.
0482: * It will perform any remaining cleanup and call notifyDestroyed.
0483: * @param success <code>true</code> if the install was a success,
0484: * <code>false</code> otherwise.
0485: */
0486: void exit(boolean success) {
0487: chmanager.installDone(success);
0488:
0489: notifyDestroyed();
0490: }
0491:
0492: /**
0493: * Respond to a command issued on any Screen.
0494: *
0495: * @param c command activated by the user
0496: * @param s the Displayable the command was on.
0497: */
0498: public void commandAction(Command c, Displayable s) {
0499: if (c == nextCmd) {
0500: // the user has entered a username and password
0501: resumeInstallWithPassword();
0502: } else if (c == okCmd) {
0503: resumeInstallAfterWarning();
0504: } else if (c == continueCmd) {
0505: startJarDownload();
0506: } else if (c == keepRMSCmd) {
0507: setKeepRMSAnswer(true);
0508: } else if (c == removeRMSCmd) {
0509: setKeepRMSAnswer(false);
0510: } else if (c == stopCmd) {
0511: if (installer != null) {
0512: /*
0513: * BackgroundInstaller may be displaying
0514: * the "Finishing" message
0515: *
0516: * also we need to prevent the BackgroundInstaller from
0517: * re-displaying the list before the cancelled message is
0518: * displayed
0519: */
0520: synchronized (this ) {
0521: if (installer.stopInstalling()) {
0522: displayCancelledMessage(cancelledMessage);
0523: }
0524: }
0525: } else {
0526: // goto back to the manager midlet
0527: exit(false);
0528: }
0529: } else if (c == cancelCmd) {
0530: displayCancelledMessage(cancelledMessage);
0531: cancelBackgroundInstall();
0532: } else if (c == Alert.DISMISS_COMMAND) {
0533: // goto back to the manager midlet
0534: exit(false);
0535: }
0536: }
0537:
0538: /**
0539: * Initialize the settings database if it doesn't exist. This may create
0540: * two entries. The first will be for the download url, the second will
0541: * be for storing the storagename of the currently selected midlet
0542: */
0543: public static void initSettings() {
0544: MIDletStateHandler midletStateHandler = MIDletStateHandler
0545: .getMidletStateHandler();
0546: MIDletSuite midletSuite = midletStateHandler.getMIDletSuite();
0547:
0548: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
0549:
0550: try {
0551: RecordStore settings = RecordStore.openRecordStore(
0552: SETTINGS_STORE, true);
0553:
0554: try {
0555: if (settings.getNumRecords() == 0) {
0556: // space for a URL
0557: settings.addRecord(null, 0, 0);
0558:
0559: // space for current MIDlet Suite name
0560: settings.addRecord(null, 0, 0);
0561: }
0562: } finally {
0563: settings.closeRecordStore();
0564: }
0565:
0566: } catch (Exception e) {
0567: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0568: Logging.report(Logging.WARNING, LogChannels.LC_AMS,
0569: "initSettings throw an Exception");
0570: }
0571: }
0572: }
0573:
0574: /**
0575: * Save the settings the user entered.
0576: *
0577: * @param url the url to save
0578: * @param curMidlet suiteId of the currently selected midlet
0579: * @return the Exception that may have been thrown, or null
0580: */
0581: public static Exception saveSettings(String url, int curMidlet) {
0582: Exception ret = null;
0583: MIDletStateHandler midletStateHandler = MIDletStateHandler
0584: .getMidletStateHandler();
0585: MIDletSuite midletSuite = midletStateHandler.getMIDletSuite();
0586:
0587: midletSuite.checkIfPermissionAllowed(Permissions.AMS);
0588:
0589: try {
0590: String temp;
0591: ByteArrayOutputStream bas;
0592: DataOutputStream dos;
0593: byte[] data;
0594: RecordStore settings;
0595:
0596: bas = new ByteArrayOutputStream();
0597: dos = new DataOutputStream(bas);
0598: settings = RecordStore.openRecordStore(SETTINGS_STORE,
0599: false);
0600:
0601: if (url != null) {
0602: dos.writeUTF(url);
0603: data = bas.toByteArray();
0604: settings.setRecord(URL_RECORD_ID, data, 0, data.length);
0605: }
0606:
0607: // Save the current midlet even if its id is
0608: // MIDletSuite.UNUSED_SUITE_ID. Otherwise in SVM mode
0609: // the last installed midlet will be always highlighted
0610: // because its it is recorded in this RMS record.
0611: bas.reset();
0612:
0613: dos.writeInt(curMidlet);
0614: data = bas.toByteArray();
0615: settings.setRecord(SELECTED_MIDLET_RECORD_ID, data, 0,
0616: data.length);
0617:
0618: settings.closeRecordStore();
0619: dos.close();
0620: } catch (Exception e) {
0621: ret = e;
0622: }
0623:
0624: return ret;
0625: }
0626:
0627: /**
0628: * Update a suite.
0629: *
0630: * @param id ID of the suite to update
0631: */
0632: private void updateSuite(int id) {
0633: MIDletSuiteImpl midletSuite = null;
0634: try {
0635: // Any runtime error will get caught by the installer
0636: midletSuite = MIDletSuiteStorage.getMIDletSuiteStorage()
0637: .getMIDletSuite(id, false);
0638: InstallInfo installInfo = midletSuite.getInstallInfo();
0639: MIDletInfo midletInfo;
0640: String name;
0641:
0642: if (midletSuite.getNumberOfMIDlets() == 1) {
0643: midletInfo = new MIDletInfo(midletSuite
0644: .getProperty("MIDlet-1"));
0645: name = midletInfo.name;
0646: } else {
0647: name = midletSuite
0648: .getProperty(MIDletSuite.SUITE_NAME_PROP);
0649: }
0650:
0651: cancelledMessage = Resource
0652: .getString(ResourceConstants.AMS_GRA_INTLR_UPD_CAN);
0653: finishingMessage = Resource
0654: .getString(ResourceConstants.AMS_GRA_INTLR_FIN_UPD);
0655: installSuiteCommon(
0656: Resource
0657: .getString(ResourceConstants.AMS_GRA_INTLR_UPDATING),
0658: name,
0659: installInfo.getDownloadUrl(),
0660: name
0661: + Resource
0662: .getString(ResourceConstants.AMS_GRA_INTLR_SUCC_UPDATED),
0663: true);
0664: } catch (MIDletSuiteLockedException e) {
0665: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0666: Logging.report(Logging.WARNING, LogChannels.LC_AMS,
0667: "updateSuite threw MIDletSuiteLockedException");
0668: }
0669: } catch (MIDletSuiteCorruptedException e) {
0670: String msg = Resource
0671: .getString(ResourceConstants.AMS_MIDLETSUITE_ID_CORRUPT_MSG)
0672: + id;
0673: Alert a = new Alert(Resource
0674: .getString(ResourceConstants.ERROR), msg, null,
0675: AlertType.ERROR);
0676: a.setTimeout(Alert.FOREVER);
0677: a.setCommandListener(this );
0678: display.setCurrent(a, new Form(""));
0679: // this Form is never displayed
0680: } finally {
0681: if (midletSuite != null) {
0682: midletSuite.close();
0683: }
0684: }
0685: }
0686:
0687: /**
0688: * Install a suite from URL.
0689: *
0690: * @param label label of the URL link
0691: * @param url HTTP/S URL of the suite to update
0692: */
0693: private void installSuite(String label, String url) {
0694: cancelledMessage = Resource
0695: .getString(ResourceConstants.AMS_GRA_INTLR_INST_CAN);
0696: finishingMessage = Resource
0697: .getString(ResourceConstants.AMS_GRA_INTLR_FIN_INST);
0698: installSuiteCommon(
0699: Resource
0700: .getString(ResourceConstants.AMS_GRA_INTLR_INSTALLING),
0701: label,
0702: url,
0703: label
0704: + Resource
0705: .getString(ResourceConstants.AMS_GRA_INTLR_SUCC_INSTALLED),
0706: false);
0707: }
0708:
0709: /**
0710: * Common helper method to install or update a suite.
0711: *
0712: * @param action action to put in the form's title
0713: * @param name name to in the form's title
0714: * @param url URL of a JAD
0715: * @param successMessage message to display to user upon success
0716: * @param updateFlag if true the current suite is being updated
0717: */
0718: private void installSuiteCommon(String action, String name,
0719: String url, String successMessage, boolean updateFlag) {
0720: try {
0721: createProgressForm(
0722: action,
0723: name,
0724: url,
0725: 0,
0726: Resource
0727: .getString(ResourceConstants.AMS_GRA_INTLR_CONN_GAUGE_LABEL));
0728: backgroundInstaller = new BackgroundInstaller(this , url,
0729: name, successMessage, updateFlag);
0730: new Thread(backgroundInstaller).start();
0731: } catch (Exception ex) {
0732: StringBuffer sb = new StringBuffer();
0733:
0734: sb.append(name);
0735: sb.append("\n");
0736: sb.append(Resource.getString(ResourceConstants.ERROR));
0737: sb.append(": ");
0738: sb.append(ex.toString());
0739: displayException(Resource
0740: .getString(ResourceConstants.AMS_CANT_ACCESS), sb
0741: .toString());
0742: }
0743: }
0744:
0745: /**
0746: * Create and display the progress form to the user with the stop action.
0747: *
0748: * @param action action to put in the form's title
0749: * @param name name to in the form's title
0750: * @param url URL of a JAD
0751: * @param size 0 if unknown, else size of object to download in K bytes
0752: * @param gaugeLabel label for progress gauge
0753: */
0754: private void createProgressForm(String action, String name,
0755: String url, int size, String gaugeLabel) {
0756: Form installForm;
0757:
0758: // display the JAR progress form
0759: installForm = displayProgressForm(action, name, url, size,
0760: gaugeLabel);
0761: installForm.addCommand(stopCmd);
0762: installForm.setCommandListener(this );
0763: }
0764:
0765: /**
0766: * Display the connecting form to the user, let call set actions.
0767: *
0768: * @param action action to put in the form's title
0769: * @param name name to in the form's title
0770: * @param url URL of a JAD
0771: * @param size 0 if unknown, else size of object to download in K bytes
0772: * @param gaugeLabel label for progress gauge
0773: *
0774: * @return displayed form
0775: */
0776: private Form displayProgressForm(String action, String name,
0777: String url, int size, String gaugeLabel) {
0778: Gauge progressGauge;
0779: StringItem urlItem;
0780:
0781: progressForm = new Form(null);
0782:
0783: progressForm.setTitle(action + " " + name);
0784:
0785: if (size <= 0) {
0786: progressGauge = new Gauge(gaugeLabel, false,
0787: Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
0788: } else {
0789: progressGauge = new Gauge(gaugeLabel, false, size, 0);
0790: }
0791:
0792: progressGaugeIndex = progressForm.append(progressGauge);
0793:
0794: if (url == null) {
0795: urlItem = new StringItem("", "");
0796: } else {
0797: urlItem = new StringItem(Resource
0798: .getString(ResourceConstants.AMS_WEBSITE)
0799: + ": ", url);
0800: }
0801:
0802: progressUrlIndex = progressForm.append(urlItem);
0803:
0804: display.setCurrent(progressForm);
0805: lastDisplayChange = System.currentTimeMillis();
0806:
0807: return progressForm;
0808: }
0809:
0810: /** Cancel an install (if there is one) waiting for user input. */
0811: private void cancelBackgroundInstall() {
0812: if (backgroundInstaller != null) {
0813: backgroundInstaller.continueInstall = false;
0814:
0815: synchronized (backgroundInstaller) {
0816: backgroundInstaller.notify();
0817: }
0818: }
0819: }
0820:
0821: /**
0822: * Update the status form.
0823: *
0824: * @param status current status of the install.
0825: * @param state current state of the install.
0826: */
0827: private void updateStatus(int status, InstallState state) {
0828: if (status == Installer.DOWNLOADING_JAD) {
0829: updateProgressForm(
0830: "",
0831: 0,
0832: Resource
0833: .getString(ResourceConstants.AMS_GRA_INTLR_DOWNLOADING_JAD_GAUGE_LABEL));
0834: return;
0835: }
0836:
0837: if (status == Installer.DOWNLOADING_JAR) {
0838: updateProgressForm(
0839: state.getJarUrl(),
0840: state.getJarSize(),
0841: Resource
0842: .getString(ResourceConstants.AMS_GRA_INTLR_DOWNLOADING_JAR_GAUGE_LABEL));
0843: return;
0844: }
0845:
0846: if (status == Installer.DOWNLOADED_1K_OF_JAR
0847: && state.getJarSize() > 0) {
0848: Gauge progressGauge = (Gauge) progressForm
0849: .get(progressGaugeIndex);
0850: progressGauge.setValue(progressGauge.getValue() + 1);
0851: return;
0852: }
0853:
0854: if (Constants.MONET_ENABLED) {
0855: if (status == Installer.GENERATING_APP_IMAGE) {
0856: updateProgressForm(
0857: null,
0858: 0,
0859: Resource
0860: .getString(ResourceConstants.AMS_GRA_INTLR_GENERATING_APP_IMAGE_GAUGE_LABEL));
0861: return;
0862: }
0863: }
0864:
0865: if (Constants.VERIFY_ONCE) {
0866: if (status == Installer.VERIFYING_SUITE_CLASSES) {
0867: if (state.getLastException() != null) {
0868: displayWarning(
0869: Resource
0870: .getString(ResourceConstants.AMS_GRA_INTLR_INSTALL_WARNING),
0871: Resource
0872: .getString(ResourceConstants.AMS_CLASS_VERIFIER_FAILURE));
0873: } else {
0874: updateProgressForm(
0875: null,
0876: 0,
0877: Resource
0878: .getString(ResourceConstants.AMS_CLASS_VERIFIER_GAUGE_LABEL));
0879: return;
0880: }
0881: }
0882: }
0883:
0884: if (status == Installer.VERIFYING_SUITE) {
0885: updateProgressForm(
0886: null,
0887: 0,
0888: Resource
0889: .getString(ResourceConstants.AMS_GRA_INTLR_VERIFYING_SUITE_GAUGE_LABEL));
0890: return;
0891: }
0892:
0893: if (status == Installer.STORING_SUITE) {
0894: updateProgressForm(null, 0, finishingMessage);
0895: return;
0896: }
0897:
0898: if (status == Installer.CORRUPTED_SUITE) {
0899: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0900: Logging.report(Logging.WARNING, LogChannels.LC_AMS,
0901: "Suite is corrupted");
0902: }
0903: return;
0904: }
0905: }
0906:
0907: /**
0908: * Prevent screen flash on a fast systems.
0909: */
0910: void preventScreenFlash() {
0911: long waitTime = ALERT_TIMEOUT
0912: - (System.currentTimeMillis() - lastDisplayChange);
0913:
0914: if (waitTime <= 0) {
0915: return;
0916:
0917: }
0918:
0919: try {
0920: Thread.sleep(waitTime);
0921: } catch (InterruptedException ie) {
0922: // ignore
0923: }
0924: }
0925:
0926: /**
0927: * Update URL and gauge of the progress form.
0928: *
0929: * @param url new URL, null to remove, "" to not change
0930: * @param size 0 if unknown, else size of object to download in K bytes
0931: * @param gaugeLabel label for progress gauge
0932: */
0933: private void updateProgressForm(String url, int size,
0934: String gaugeLabel) {
0935: Gauge oldProgressGauge;
0936: Gauge progressGauge;
0937: StringItem urlItem;
0938:
0939: // We need to prevent "flashing" on fast development platforms.
0940: preventScreenFlash();
0941:
0942: if (size <= 0) {
0943: progressGauge = new Gauge(gaugeLabel, false,
0944: Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
0945: } else {
0946: progressGauge = new Gauge(gaugeLabel, false, size, 0);
0947: }
0948:
0949: oldProgressGauge = (Gauge) progressForm.get(progressGaugeIndex);
0950: progressForm.set(progressGaugeIndex, progressGauge);
0951:
0952: // this ends the background thread of gauge.
0953: oldProgressGauge.setValue(Gauge.CONTINUOUS_IDLE);
0954:
0955: if (url == null) {
0956: urlItem = new StringItem("", "");
0957: progressForm.set(progressUrlIndex, urlItem);
0958: } else if (url.length() != 0) {
0959: urlItem = new StringItem(Resource
0960: .getString(ResourceConstants.AMS_WEBSITE)
0961: + ": ", url);
0962: progressForm.set(progressUrlIndex, urlItem);
0963: }
0964:
0965: lastDisplayChange = System.currentTimeMillis();
0966: }
0967:
0968: /**
0969: * Give the user a chance to act on warning during an installation.
0970: *
0971: * @param name name of the MIDlet suite to insert into the message
0972: * @param vendor vendor of the MIDlet suite to insert into the message,
0973: * can be null
0974: * @param version version of the MIDlet suite to insert into the message,
0975: * can be null
0976: * @param jadUrl URL of a JAD, can be null
0977: * @param e last exception from the installer
0978: */
0979: private void warnUser(String name, String vendor, String version,
0980: String jadUrl, InvalidJadException e) {
0981: Form warningForm;
0982:
0983: warningForm = new Form(null);
0984: warningForm.setTitle(Resource
0985: .getString(ResourceConstants.WARNING));
0986: warningForm.append(translateJadException(e, name, vendor,
0987: version, jadUrl));
0988: warningForm.addCommand(cancelCmd);
0989: warningForm.addCommand(okCmd);
0990: warningForm.setCommandListener(this );
0991: display.setCurrent(warningForm);
0992: }
0993:
0994: /**
0995: * Resume the install after a the user overrides a warning.
0996: */
0997: private void resumeInstallAfterWarning() {
0998: // redisplay the progress form
0999: display.setCurrent(progressForm);
1000:
1001: backgroundInstaller.continueInstall = true;
1002: synchronized (backgroundInstaller) {
1003: backgroundInstaller.notify();
1004: }
1005: }
1006:
1007: /**
1008: * Ask for a username and password.
1009: */
1010: private void getUsernameAndPassword() {
1011: getUsernameAndPasswordCommon("");
1012: }
1013:
1014: /**
1015: * Ask for proxy username and password.
1016: */
1017: private void getProxyUsernameAndPassword() {
1018: getUsernameAndPasswordCommon(Resource
1019: .getString(ResourceConstants.AMS_GRA_INTLR_PASSWORD_FORM_FIREWALL_TITLE));
1020: }
1021:
1022: /**
1023: * Ask a username and password.
1024: *
1025: * @param title title of the password form
1026: */
1027: private void getUsernameAndPasswordCommon(String title) {
1028: if (passwordForm == null) {
1029: passwordForm = new Form(null);
1030:
1031: usernameField = new TextField(
1032: Resource
1033: .getString(ResourceConstants.AMS_GRA_INTLR_ENTER_ID),
1034: null, 40, TextField.ANY);
1035: passwordForm.append(usernameField);
1036:
1037: passwordField = new TextField(
1038: Resource
1039: .getString(ResourceConstants.AMS_GRA_INTLR_PASSWORD),
1040: null, 40, TextField.PASSWORD);
1041: passwordForm.append(passwordField);
1042: passwordForm.addCommand(cancelCmd);
1043: passwordForm.addCommand(nextCmd);
1044: passwordForm.setCommandListener(this );
1045: }
1046:
1047: passwordForm.setTitle(title);
1048: passwordField.setString("");
1049: display.setCurrent(passwordForm);
1050: }
1051:
1052: /**
1053: * Resume the install of the suite with a password and username.
1054: */
1055: private void resumeInstallWithPassword() {
1056: String username;
1057: String password;
1058:
1059: username = usernameField.getString();
1060: password = passwordField.getString();
1061: if (username == null || username.length() == 0) {
1062: Alert a = new Alert(
1063: Resource.getString(ResourceConstants.ERROR),
1064: Resource
1065: .getString(ResourceConstants.AMS_GRA_INTLR_ID_NOT_ENTERED),
1066: null, AlertType.ERROR);
1067: a.setTimeout(ALERT_TIMEOUT);
1068: display.setCurrent(a, passwordForm);
1069: return;
1070: }
1071:
1072: if (password == null || password.length() == 0) {
1073: Alert a = new Alert(
1074: Resource.getString(ResourceConstants.ERROR),
1075: Resource
1076: .getString(ResourceConstants.AMS_GRA_INTLR_PWD_NOT_ENTERED),
1077: null, AlertType.ERROR);
1078: a.setTimeout(ALERT_TIMEOUT);
1079: display.setCurrent(a, passwordForm);
1080: return;
1081: }
1082:
1083: // redisplay the progress form
1084: display.setCurrent(progressForm);
1085:
1086: if (backgroundInstaller.proxyAuth) {
1087: backgroundInstaller.installState.setProxyUsername(username);
1088: backgroundInstaller.installState.setProxyPassword(password);
1089: } else {
1090: backgroundInstaller.installState.setUsername(username);
1091: backgroundInstaller.installState.setPassword(password);
1092: }
1093:
1094: backgroundInstaller.continueInstall = true;
1095: synchronized (backgroundInstaller) {
1096: backgroundInstaller.notify();
1097: }
1098: }
1099:
1100: /**
1101: * Confirm the JAR download with the user.
1102: *
1103: * @param state current state of the install.
1104: */
1105: private void displayDownloadConfirmation(InstallState state) {
1106: Form infoForm;
1107: StringItem item;
1108: String name;
1109: String desc;
1110: StringBuffer label = new StringBuffer(40);
1111: StringBuffer value = new StringBuffer(40);
1112: String[] values = new String[1];
1113:
1114: name = state.getSuiteName();
1115:
1116: try {
1117: infoForm = new Form(null);
1118:
1119: infoForm.setTitle(Resource
1120: .getString(ResourceConstants.AMS_CONFIRMATION));
1121:
1122: values[0] = name;
1123: item = new StringItem(null, Resource.getString(
1124: ResourceConstants.AMS_GRA_INTLR_WANT_INSTALL,
1125: values));
1126: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1127: infoForm.append(item);
1128:
1129: if (!installer.isJadSigned()) {
1130: // The MIDlet suite is not signed, therefore will be untrusted
1131: item = new StringItem(
1132: Resource.getString(ResourceConstants.WARNING)
1133: + ":",
1134: Resource
1135: .getString(ResourceConstants.AMS_GRA_INTLR_UNTRUSTED_WARN));
1136: item.setLayout(Item.LAYOUT_NEWLINE_AFTER
1137: | Item.LAYOUT_2);
1138: infoForm.append(item);
1139: }
1140:
1141: // round up the size to a Kilobyte
1142: label
1143: .append(Resource
1144: .getString(ResourceConstants.AMS_SIZE));
1145: label.append(": ");
1146: value.setLength(0);
1147: value.append(state.getJarSize());
1148: value.append(" K");
1149: item = new StringItem(label.toString(), value.toString());
1150: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1151: infoForm.append(item);
1152:
1153: label.setLength(0);
1154: label.append(Resource
1155: .getString(ResourceConstants.AMS_VERSION));
1156: label.append(": ");
1157: value.setLength(0);
1158: item = new StringItem(label.toString(), state
1159: .getAppProperty(MIDletSuite.VERSION_PROP));
1160: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1161: infoForm.append(item);
1162:
1163: label.setLength(0);
1164: label.append(Resource
1165: .getString(ResourceConstants.AMS_VENDOR));
1166: label.append(": ");
1167: item = new StringItem(label.toString(), state
1168: .getAppProperty(MIDletSuite.VENDOR_PROP));
1169: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1170: infoForm.append(item);
1171:
1172: desc = state.getAppProperty(MIDletSuite.DESC_PROP);
1173: if (desc != null) {
1174: label.setLength(0);
1175: label.append(Resource
1176: .getString(ResourceConstants.AMS_DESCRIPTION));
1177: label.append(": ");
1178: item = new StringItem(label.toString(), desc);
1179: item.setLayout(Item.LAYOUT_NEWLINE_AFTER
1180: | Item.LAYOUT_2);
1181: infoForm.append(item);
1182: }
1183:
1184: label.setLength(0);
1185: label.append(Resource
1186: .getString(ResourceConstants.AMS_WEBSITE));
1187: label.append(": ");
1188: infoForm.append(new StringItem(label.toString(), state
1189: .getJarUrl()));
1190:
1191: infoForm.addCommand(continueCmd);
1192: infoForm.addCommand(cancelCmd);
1193: infoForm.setCommandListener(this );
1194:
1195: // We need to prevent "flashing" on fast development platforms.
1196: preventScreenFlash();
1197:
1198: display.setCurrent(infoForm);
1199: } catch (Exception ex) {
1200: StringBuffer sb = new StringBuffer();
1201:
1202: sb.append(name);
1203: sb.append("\n");
1204: sb.append(Resource.getString(ResourceConstants.EXCEPTION));
1205: sb.append(": ");
1206: sb.append(ex.toString());
1207: displayException(Resource
1208: .getString(ResourceConstants.AMS_CANT_ACCESS), sb
1209: .toString());
1210: }
1211: }
1212:
1213: /**
1214: * Ask the user during an update if they want to keep the old RMS data.
1215: *
1216: * @param state current state of the install.
1217: */
1218: private void displayKeepRMSForm(InstallState state) {
1219: Form infoForm;
1220: String name;
1221: String desc;
1222: StringBuffer label = new StringBuffer(40);
1223: StringBuffer value = new StringBuffer(40);
1224: String[] values = new String[1];
1225:
1226: name = state.getAppProperty(MIDletSuite.SUITE_NAME_PROP);
1227:
1228: try {
1229: infoForm = new Form(null);
1230:
1231: infoForm.setTitle(Resource
1232: .getString(ResourceConstants.AMS_CONFIRMATION));
1233:
1234: values[0] = name;
1235: value.append(Resource.getString(
1236: ResourceConstants.AMS_GRA_INTLR_NEW_OLD_VERSION,
1237: values));
1238: infoForm.append(value.toString());
1239:
1240: infoForm.addCommand(keepRMSCmd);
1241: infoForm.addCommand(removeRMSCmd);
1242: infoForm.setCommandListener(this );
1243:
1244: // We need to prevent "flashing" on fast development platforms.
1245: preventScreenFlash();
1246:
1247: display.setCurrent(infoForm);
1248: } catch (Exception ex) {
1249: StringBuffer sb = new StringBuffer();
1250:
1251: sb.append(name);
1252: sb.append("\n");
1253: sb.append(Resource.getString(ResourceConstants.EXCEPTION));
1254: sb.append(": ");
1255: sb.append(ex.toString());
1256: displayException(Resource
1257: .getString(ResourceConstants.AMS_CANT_ACCESS), sb
1258: .toString());
1259: }
1260: }
1261:
1262: /**
1263: * Confirm the authorization path with the user.
1264: *
1265: * @param state current state of the install.
1266: */
1267: private void displayAuthPathConfirmation(InstallState state) {
1268: Form infoForm;
1269: String name;
1270: String values[] = new String[1];
1271: StringItem item;
1272: String authPath[];
1273: String temp;
1274: StringBuffer label = new StringBuffer(40);
1275: StringBuffer value = new StringBuffer(40);
1276:
1277: name = state.getAppProperty(MIDletSuite.SUITE_NAME_PROP);
1278:
1279: try {
1280: infoForm = new Form(
1281: Resource
1282: .getString(ResourceConstants.AMS_AUTHORIZATION_INFO));
1283:
1284: infoForm.append(new ImageItem(null, TrustedMIDletIcon
1285: .getIcon(), ImageItem.LAYOUT_NEWLINE_BEFORE
1286: | ImageItem.LAYOUT_CENTER
1287: | ImageItem.LAYOUT_NEWLINE_AFTER, null));
1288:
1289: values[0] = name;
1290: label.setLength(0);
1291: label.append(Resource.getString(
1292: ResourceConstants.AMS_GRA_INTLR_TRUSTED, values));
1293: label.append(": ");
1294:
1295: authPath = state.getAuthPath();
1296: temp = label.toString();
1297: for (int i = 0; i < authPath.length; i++) {
1298: item = new StringItem(temp, authPath[i]);
1299: item.setLayout(Item.LAYOUT_NEWLINE_AFTER
1300: | Item.LAYOUT_2);
1301: infoForm.append(item);
1302: temp = " -> ";
1303: }
1304:
1305: infoForm.addCommand(continueCmd);
1306: infoForm.addCommand(cancelCmd);
1307: infoForm.setCommandListener(this );
1308:
1309: // We need to prevent "flashing" on fast development platforms.
1310: preventScreenFlash();
1311:
1312: display.setCurrent(infoForm);
1313: } catch (Exception ex) {
1314: StringBuffer sb = new StringBuffer();
1315:
1316: sb.append(Resource.getString(ResourceConstants.EXCEPTION));
1317: sb.append(": ");
1318: sb.append(ex.toString());
1319: displayException(Resource
1320: .getString(ResourceConstants.AMS_CANT_ACCESS), sb
1321: .toString());
1322: }
1323: }
1324:
1325: /**
1326: * Resume the install to start the JAR download.
1327: */
1328: private void startJarDownload() {
1329: updateProgressForm(
1330: backgroundInstaller.url,
1331: 0,
1332: Resource
1333: .getString(ResourceConstants.AMS_GRA_INTLR_CONN_GAUGE_LABEL));
1334: // redisplay the progress form
1335: display.setCurrent(progressForm);
1336:
1337: backgroundInstaller.continueInstall = true;
1338: synchronized (backgroundInstaller) {
1339: backgroundInstaller.notify();
1340: }
1341: }
1342:
1343: /** Confirm the JAR only download with the user. */
1344: private void displayJarOnlyDownloadConfirmation() {
1345: Form infoForm;
1346: StringItem item;
1347: StringBuffer label = new StringBuffer(40);
1348: StringBuffer value = new StringBuffer(40);
1349: String[] values = new String[1];
1350:
1351: try {
1352: infoForm = new Form(null);
1353:
1354: infoForm.setTitle(Resource
1355: .getString(ResourceConstants.AMS_CONFIRMATION));
1356:
1357: values[0] = backgroundInstaller.name;
1358: item = new StringItem(null, Resource.getString(
1359: ResourceConstants.AMS_GRA_INTLR_WANT_INSTALL,
1360: values));
1361: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1362: infoForm.append(item);
1363:
1364: label.append(Resource
1365: .getString(ResourceConstants.AMS_WEBSITE));
1366: label.append(": ");
1367: item = new StringItem(label.toString(),
1368: backgroundInstaller.url);
1369: item.setLayout(Item.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);
1370: infoForm.append(item);
1371:
1372: value.append(" \n");
1373: value
1374: .append(Resource
1375: .getString(ResourceConstants.AMS_GRA_INTLR_NO_INFO));
1376: infoForm.append(new StringItem(null, value.toString()));
1377:
1378: infoForm.addCommand(continueCmd);
1379: infoForm.addCommand(cancelCmd);
1380: infoForm.setCommandListener(this );
1381:
1382: // We need to prevent "flashing" on fast development platforms.
1383: preventScreenFlash();
1384:
1385: display.setCurrent(infoForm);
1386: } catch (Exception ex) {
1387: StringBuffer sb = new StringBuffer();
1388:
1389: sb.append(backgroundInstaller.name);
1390: sb.append("\n");
1391: sb.append(Resource.getString(ResourceConstants.EXCEPTION));
1392: sb.append(": ");
1393: sb.append(ex.toString());
1394: displayException(Resource
1395: .getString(ResourceConstants.AMS_CANT_ACCESS), sb
1396: .toString());
1397: }
1398: }
1399:
1400: /**
1401: * Tell the background installer to keep the RMS data.
1402: *
1403: * @param keepRMS set to true to mean the user answered yes
1404: */
1405: private void setKeepRMSAnswer(boolean keepRMS) {
1406: // redisplay the progress form
1407: display.setCurrent(progressForm);
1408:
1409: // We need to prevent "flashing" on fast development platforms.
1410: preventScreenFlash();
1411:
1412: backgroundInstaller.continueInstall = keepRMS;
1413: synchronized (backgroundInstaller) {
1414: backgroundInstaller.notify();
1415: }
1416: }
1417:
1418: /**
1419: * Alert the user that an action was successful.
1420: *
1421: * @param successMessage message to display to user
1422: */
1423: private void displaySuccessMessage(String successMessage) {
1424: Image icon;
1425: Alert successAlert;
1426:
1427: icon = getImageFromInternalStorage("_dukeok8");
1428:
1429: successAlert = new Alert(null, successMessage, icon, null);
1430:
1431: successAlert.setTimeout(Alert.FOREVER);
1432:
1433: // Provide a listener to disable the advance-to-next-displayable
1434: // feature of Alert.
1435: successAlert.setCommandListener(new CommandListener() {
1436: public void commandAction(Command c, Displayable d) {
1437: }
1438: });
1439:
1440: // We need to prevent "flashing" on fast development platforms.
1441: preventScreenFlash();
1442:
1443: lastDisplayChange = System.currentTimeMillis();
1444: display.setCurrent(successAlert, new Form(""));
1445: // this Form is never displayed
1446: }
1447:
1448: /**
1449: * Alert the user that an action was canceled. The backgroundInstaller
1450: * will hide the message.
1451: * @param message message to display to user
1452: */
1453: private void displayCancelledMessage(String message) {
1454: Form form;
1455: Image icon;
1456:
1457: form = new Form(null);
1458:
1459: icon = getImageFromInternalStorage("_ack8");
1460: form.append(new ImageItem(null, icon, ImageItem.LAYOUT_CENTER
1461: + ImageItem.LAYOUT_NEWLINE_BEFORE
1462: + ImageItem.LAYOUT_NEWLINE_AFTER, null));
1463:
1464: form.append(message);
1465:
1466: display.setCurrent(form);
1467: lastDisplayChange = System.currentTimeMillis();
1468: }
1469:
1470: /**
1471: * Display an alert to the user, with a done command.
1472: *
1473: * @param title alert's title
1474: * @param message alert message
1475: * @param type severity of the alert message
1476: */
1477: private void displayAlert(String title, String message,
1478: AlertType type) {
1479:
1480: Alert a = new Alert(title, message, null, type);
1481:
1482: a.setTimeout(Alert.FOREVER);
1483: a.setCommandListener(this );
1484:
1485: display.setCurrent(a, new Form(""));
1486: // this Form is never displayed
1487: }
1488:
1489: /**
1490: * Display an warning to the user, with a done command.
1491: *
1492: * @param title warnings form's title
1493: * @param message warning message
1494: */
1495: private void displayWarning(String title, String message) {
1496: displayAlert(title, message, AlertType.WARNING);
1497: }
1498:
1499: /**
1500: * Display an exception to the user, with a done command.
1501: *
1502: * @param title exception form's title
1503: * @param message exception message
1504: */
1505: private void displayException(String title, String message) {
1506: displayAlert(title, message, AlertType.ERROR);
1507: }
1508:
1509: /** A class to install a suite in a background thread. */
1510: private class BackgroundInstaller implements Runnable,
1511: InstallListener {
1512: /** Parent installer. */
1513: private GraphicalInstaller parent;
1514: /** URL to install from. */
1515: private String url;
1516: /** Name of MIDlet suite. */
1517: private String name;
1518: /**
1519: * Message for the user after the current install completes
1520: * successfully.
1521: */
1522: private String successMessage;
1523: /** Flag to update the current suite. */
1524: private boolean update;
1525: /** State of the install. */
1526: InstallState installState;
1527: /** Signals that the user wants the install to continue. */
1528: boolean continueInstall;
1529: /** Signals that the suite only has JAR, no JAD. */
1530: boolean jarOnly;
1531: /** Signals that a proxyAuth is needed. */
1532: boolean proxyAuth;
1533:
1534: /**
1535: * Construct a BackgroundInstaller.
1536: *
1537: * @param theParent parent installer of this object
1538: * @param theJadUrl where to get the JAD.
1539: * @param theName name of the MIDlet suite
1540: * @param theSuccessMessage message to display to user upon success
1541: * @param updateFlag if true the current suite should be
1542: * overwritten without asking the user.
1543: */
1544: private BackgroundInstaller(GraphicalInstaller theParent,
1545: String theJadUrl, String theName,
1546: String theSuccessMessage, boolean updateFlag) {
1547: parent = theParent;
1548: url = theJadUrl;
1549: name = theName;
1550: successMessage = theSuccessMessage;
1551: update = updateFlag;
1552: }
1553:
1554: /**
1555: * Run the installer.
1556: */
1557: public void run() {
1558: // ID of the suite that was just installed
1559: int lastInstalledMIDletId = MIDletSuite.UNUSED_SUITE_ID;
1560:
1561: try {
1562: // a flag indicating that an attempt of installation must
1563: // be repeated, but now using the jar URL instead of jad
1564: boolean tryAgain;
1565: // title of the window displaying an error message
1566: String title;
1567: // an error message to display
1568: String msg;
1569:
1570: // repeat while(tryAgain)
1571: do {
1572: tryAgain = false;
1573: msg = null;
1574:
1575: try {
1576: if (jarOnly) {
1577: lastInstalledMIDletId = parent.installer
1578: .installJar(url, name, storageId,
1579: false, false, this );
1580: } else {
1581: lastInstalledMIDletId = parent.installer
1582: .installJad(url, storageId, false,
1583: false, this );
1584: }
1585:
1586: // Let the manager know what suite was installed
1587: GraphicalInstaller.saveSettings(null,
1588: lastInstalledMIDletId);
1589:
1590: parent.displaySuccessMessage(successMessage);
1591:
1592: /*
1593: * We need to prevent "flashing" on fast development
1594: * platforms.
1595: */
1596: parent.preventScreenFlash();
1597:
1598: parent.exit(true);
1599: } catch (InvalidJadException ije) {
1600: if (ije.getReason() == InvalidJadException.INVALID_JAD_TYPE) {
1601: // media type of JAD was wrong, it could be a JAR
1602: String mediaType = (String) ije
1603: .getExtraData();
1604:
1605: if (Installer.JAR_MT_1.equals(mediaType)
1606: || Installer.JAR_MT_2
1607: .equals(mediaType)) {
1608: // re-run as a JAR only install
1609: if (confirmJarOnlyDownload()) {
1610: jarOnly = true;
1611: installState = null;
1612: tryAgain = true;
1613: continue;
1614: }
1615:
1616: displayListAfterCancelMessage();
1617: break;
1618: }
1619: }
1620:
1621: msg = translateJadException(ije, name, null,
1622: null, url);
1623: } catch (MIDletSuiteLockedException msle) {
1624: String[] values = new String[1];
1625: values[0] = name;
1626: if (!update) {
1627: msg = Resource
1628: .getString(
1629: ResourceConstants.AMS_DISC_APP_LOCKED,
1630: values);
1631: } else {
1632: msg = Resource
1633: .getString(
1634: ResourceConstants.AMS_GRA_INTLR_LOCKED,
1635: values);
1636: }
1637: } catch (IOException ioe) {
1638: if (parent.installer != null
1639: && parent.installer.wasStopped()) {
1640: displayListAfterCancelMessage();
1641: break;
1642: } else {
1643: msg = Resource
1644: .getString(ResourceConstants.AMS_GRA_INTLR_CONN_DROPPED);
1645: }
1646: } catch (Throwable ex) {
1647: if (Logging.TRACE_ENABLED) {
1648: Logging.trace(ex, "Exception caught "
1649: + "while installing");
1650: }
1651:
1652: msg = ex.getClass().getName() + ": "
1653: + ex.getMessage();
1654: }
1655:
1656: } while (tryAgain);
1657:
1658: // display an error message, if any
1659: if (msg != null) {
1660: title = Resource
1661: .getString(ResourceConstants.AMS_GRA_INTLR_INSTALL_ERROR);
1662: // go back to the app list
1663: displayException(title, msg);
1664: }
1665: } finally {
1666: if (lastInstalledMIDletId == MIDletSuite.UNUSED_SUITE_ID) {
1667: // Reset an ID of the last successfully installed midlet
1668: // because an error has occured.
1669: GraphicalInstaller.saveSettings(null,
1670: MIDletSuite.UNUSED_SUITE_ID);
1671: }
1672:
1673: if (parent.progressForm != null) {
1674: // end the background thread of progress gauge.
1675: Gauge progressGauge = (Gauge) parent.progressForm
1676: .get(parent.progressGaugeIndex);
1677: progressGauge.setValue(Gauge.CONTINUOUS_IDLE);
1678: }
1679: }
1680: }
1681:
1682: /**
1683: * Called with the current state of the install so the user can be
1684: * asked to override the warning. Calls the parent to display the
1685: * warning to the user and then waits on the state object for
1686: * user's response.
1687: *
1688: * @param state current state of the install.
1689: *
1690: * @return true if the user wants to continue,
1691: * false to stop the install
1692: */
1693: public boolean warnUser(InstallState state) {
1694: installState = state;
1695:
1696: InvalidJadException e = installState.getLastException();
1697:
1698: switch (e.getReason()) {
1699: case InvalidJadException.UNAUTHORIZED:
1700: proxyAuth = false;
1701: parent.getUsernameAndPassword();
1702: break;
1703:
1704: case InvalidJadException.PROXY_AUTH:
1705: proxyAuth = true;
1706: parent.getProxyUsernameAndPassword();
1707: break;
1708:
1709: case InvalidJadException.OLD_VERSION:
1710: case InvalidJadException.ALREADY_INSTALLED:
1711: case InvalidJadException.NEW_VERSION:
1712: // this is now an update
1713: update = true;
1714:
1715: // fall through
1716: default:
1717: parent.warnUser(name, state
1718: .getAppProperty(MIDletSuite.VENDOR_PROP), state
1719: .getAppProperty(MIDletSuite.VERSION_PROP), url,
1720: e);
1721: }
1722:
1723: return waitForUser();
1724: }
1725:
1726: /**
1727: * Called with the current state of the install so the user can be
1728: * asked to confirm the jar download.
1729: * If false is returned, the an I/O exception thrown and
1730: * {@link Installer#wasStopped()} will return true if called.
1731: *
1732: * @param state current state of the install.
1733: *
1734: * @return true if the user wants to continue, false to stop the
1735: * install
1736: */
1737: public boolean confirmJarDownload(InstallState state) {
1738: if (update) {
1739: // this an update, no need to confirm.
1740: return true;
1741: }
1742:
1743: installState = state;
1744:
1745: url = state.getJarUrl();
1746:
1747: parent.displayDownloadConfirmation(state);
1748: return waitForUser();
1749: }
1750:
1751: /**
1752: * Called with the current state of the install so the user can be
1753: * asked to confirm if the RMS data should be kept for new version of
1754: * an updated suite.
1755: *
1756: * @param state current state of the install.
1757: *
1758: * @return true if the user wants to keep the RMS data for the next
1759: * suite
1760: */
1761: public boolean keepRMS(InstallState state) {
1762: installState = state;
1763:
1764: parent.displayKeepRMSForm(state);
1765: return waitForUser();
1766: }
1767:
1768: /**
1769: * Called with the current state of the install so the user can be
1770: * asked to confirm the authentication path.
1771: * If false is returned, the an I/O exception thrown and
1772: * {@link Installer#wasStopped()} will return true if called.
1773: *
1774: * @param state current state of the install.
1775: *
1776: * @return true if the user wants to continue, false to stop the
1777: * install
1778: */
1779: public boolean confirmAuthPath(InstallState state) {
1780: parent.displayAuthPathConfirmation(state);
1781: return waitForUser();
1782: }
1783:
1784: /**
1785: * Called with the current state of the install so the user can be
1786: * asked to confirm the jar only download.
1787: *
1788: * @return true if the user wants to continue, false to stop the
1789: * install
1790: */
1791: private boolean confirmJarOnlyDownload() {
1792: if (update) {
1793: // this an update, no need to confirm.
1794: return true;
1795: }
1796:
1797: parent.displayJarOnlyDownloadConfirmation();
1798: return waitForUser();
1799: }
1800:
1801: /**
1802: * Wait for the user to respond to current dialog.
1803: *
1804: * @return true if the user wants to continue, false to stop the
1805: * install
1806: */
1807: private boolean waitForUser() {
1808: boolean temp;
1809:
1810: synchronized (this ) {
1811: try {
1812: this .wait();
1813: } catch (InterruptedException ie) {
1814: if (Logging.REPORT_LEVEL <= Logging.WARNING) {
1815: Logging.report(Logging.WARNING,
1816: LogChannels.LC_AMS,
1817: "wait threw an InterruptedException");
1818: }
1819: }
1820: }
1821:
1822: installState = null;
1823:
1824: temp = continueInstall;
1825: continueInstall = false;
1826:
1827: return temp;
1828: }
1829:
1830: /**
1831: * Called with the current status of the install.
1832: * Changes the status alert box text based on the status.
1833: *
1834: * @param status current status of the install.
1835: * @param state current state of the install.
1836: */
1837: public void updateStatus(int status, InstallState state) {
1838: parent.updateStatus(status, state);
1839: }
1840:
1841: /**
1842: * Wait for the cancel message to be displayed to prevent flashing
1843: * and then display the list of suites.
1844: */
1845: private void displayListAfterCancelMessage() {
1846: // wait for the parent to display "cancelled"
1847: synchronized (parent) {
1848: /*
1849: * We need to prevent "flashing" on fast
1850: * development platforms.
1851: */
1852: parent.preventScreenFlash();
1853:
1854: // go back to app list
1855: parent.exit(false);
1856: }
1857: }
1858: }
1859: }
|