javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/midp2/install/steps/FinalizeInstallation.java
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 16:30:29 +0300
branchRCL_3
changeset 19 04becd199f91
child 35 85266cc22c7f
child 60 6c158198356e
permissions -rw-r--r--
Revision: v2.1.22 Kit: 201017

/*
* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/


package com.nokia.mj.impl.installer.midp2.install.steps;

import com.nokia.mj.impl.installer.ui.ApplicationInfo;
import com.nokia.mj.impl.installer.ui.LaunchAppInfo;
import com.nokia.mj.impl.installer.applicationregistrator.ApplicationRegistrator;
import com.nokia.mj.impl.installer.captainservice.CaptainService;
import com.nokia.mj.impl.installer.exetable.ExeBall;
import com.nokia.mj.impl.installer.exetable.ExeStep;
import com.nokia.mj.impl.installer.Installer;
import com.nokia.mj.impl.installer.utils.FileUtils;
import com.nokia.mj.impl.installer.utils.InstallerException;
import com.nokia.mj.impl.installer.utils.Log;
import com.nokia.mj.impl.installer.utils.Platform;
import com.nokia.mj.impl.utils.Uid;

import java.io.InputStream;
import java.io.IOException;
import java.util.Vector;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;

public class FinalizeInstallation extends ExeStep
{
    // JarFile instance, used for getting icon InputStreams.
    private JarFile iJarFile = null;

    public void execute(ExeBall aBall)
    {
        InstallBall ball = (InstallBall)aBall;
        ball.log("Finalizing installation...");

        // If posting OTA status notifications is still going on,
        // stop it now and continue when next installation is made.
        ball.getNotificationPoster().stop();

        // Cleanup security components.
        ball.cleanupSecurity();

        // If -forcecancel option was specified, abort execution
        // before committing anything.
        if (ball.iArgs.get("forcecancel") != null)
        {
            InstallerException.internalError("FORCED CANCEL");
        }

        // User is not allowed to cancel installation after this step.
        ball.setCanCancel(false);

        checkWaitAttribute(ball, "before storage commit");

        // StorageHandler must be committed before ApplicationRegistrator
        // so that platform specific application registry can use the data
        // in Java Storage (S60 AppArc application list re-scan)
        ball.iStorageHandler.commitSession();

        // StorageHandler commit is asynchronous. In case of
        // conversion installation or preinstallation wait for
        // a while so that the commit can be done before the
        // application registrator commit causes accesses to
        // Storage (S60 AppArc application list re-scan)
        if (ball.iConversionInstallation ||
                ball.iPreinstallation)
        {
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException ie)
                { }
        }

        Log.log("StorageHandler committed");

        checkWaitAttribute(ball, "after storage commit");

        ball.iSifRegistrator.commitSession();
        Log.log("SifRegistrator committed");

        checkWaitAttribute(ball, "after sif commit");

        // ApplicationRegistrator session must be commited before
        // IntegrityService session so that temp icon files
        // can be removed.
        // Make synchronous commit so that the application
        // becomes visible to all parts of the system before
        // installer finishes.
        ball.iApplicationRegistrator.commitSession(true);

        Log.log("ApplicationRegistrator committed");

        checkWaitAttribute(ball, "after apparc commit");

        boolean result = ball.iIntegrityService.commit();
        if (!result)
        {
            InstallerException.internalError("IntegrityService commit failed");
        }
        Log.log("IntegrityService committed");

        checkWaitAttribute(ball, "after integrityservice commit");

        ball.iInstallationNotifier.finish(
            ball.iSuite.getUid(), ball.iInstallationNotifier.INSTALL_OK);

        // All sessions have been committed, do not throw
        // exceptions anymore after this point!

        Uid[] uids = ball.iSuite.getApplicationUids();

        try
        {
            // Notify platform that applications have been added or updated.
            ball.iSifRegistrator.notifyAppChange(
                uids, (ball.iOldSuite != null?
                       ball.iSifRegistrator.APP_UPDATED:
                       ball.iSifRegistrator.APP_ADDED));
        }
        catch (Throwable t)
        {
            Log.logError("SifRegistrator.notifyAppChange failed", t);
        }

        if (ball.iCaptainMsgs)
        {
            // Notify JavaCaptain that application has been installed.
            Uid[] oldUids = null;
            if (ball.iOldSuite != null)
            {
                oldUids = ball.iOldSuite.getApplicationUids();
            }
            ball.getCaptainService().appUpdated(oldUids, uids);
            Log.log("JavaCaptain notified");
        }

        String midletName = ball.getAttributeValue("MIDlet-Name");
        ball.log("Application " + midletName + " successfully installed.");
        ball.log(ball.iSuite.toShortString());

        // Store the uids to Installer static variable
        // in case CommsInstaller has to send them to
        // TCK Runner or preinstaller
        Installer.setInstalledUids(ball.iSuite.getUid(), uids);

        if (!ball.isSilent())
        {
            if (ball.getInstallerUi() != null && Platform.isS60())
            {
                if (ball.LAUNCH_APP_QUERY)
                {
                    // Set installation progress to 100% before
                    // displaying application launch query.
                    ball.iInstallationNotifier.set(
                        ball.iInstallationNotifier.getMax());
                    // Display launch application query to the user.
                    createLaunchAppQueryThread(ball);
                }
            }
            if (Platform.isLinux() && ball.iCaptainMsgs)
            {
                // Launch the installed application
                try
                {
                    // CaptainService.launchApp() uses RLC message.
                    //ball.getCaptainService().launchApp(uids[0]);
                    // CaptainService.startApp() uses installer specific
                    // message.
                    ball.getCaptainService().startApp(new Uid[] { uids[0] });
                }
                catch (InstallerException ie)
                {
                    Log.log("Launching application failed: " + ie.toString());
                }
            }
        }
    }

    public void cancel(ExeBall aBall)
    {
        // nop
    }

    /**
     * Constructs a new LaunchAppInfo object basing on given InstallBall.
     */
    private LaunchAppInfo createLaunchAppInfo(InstallBall aBall)
    {
        // Get suite icon InputStream.
        InputStream suiteIconInputStream = null;
        String suiteIconPath = aBall.iSuite.getAttributeValue("MIDlet-Icon");
        if (suiteIconPath != null)
        {
            try
            {
                if (iJarFile == null)
                {
                    // Temp files have already been deleted,
                    // get the icon from installed jar file.
                    iJarFile = new JarFile(aBall.iSuite.getJarPath());
                }
                suiteIconInputStream =
                    iJarFile.getInputStream
                    (new JarEntry(FileUtils.trimJarEntry(suiteIconPath)));
                Log.log("LaunchAppInfo: suite icon " + suiteIconPath);
            }
            catch (IOException ioe)
            {
                Log.logWarning("Getting InputStream for suite icon failed", ioe);
            }
        }

        // Get application icon InputStreams.
        InputStream[] appIconInputStreams = null;
        Vector appInfos = aBall.iSuite.getApplications();
        if (appInfos != null)
        {
            appIconInputStreams = new InputStream[appInfos.size()];
            try
            {
                if (iJarFile == null)
                {
                    // Temp files have already been deleted,
                    // get the icon from installed jar file.
                    iJarFile = new JarFile(aBall.iSuite.getJarPath());
                }
                for (int i = 0; i < appIconInputStreams.length; i++)
                {
                    String iconPath =
                        ((com.nokia.mj.impl.installer.storagehandler.ApplicationInfo)
                         appInfos.elementAt(i)).getIconPath();
                    if (iconPath != null && iconPath.length() > 0)
                    {
                        appIconInputStreams[i] =
                            iJarFile.getInputStream
                            (new JarEntry(FileUtils.trimJarEntry(iconPath)));
                        Log.log("LaunchAppInfo: app icon " + i + ": " + iconPath);
                    }
                    else
                    {
                        appIconInputStreams[i] = null;
                        Log.log("LaunchAppInfo: app icon " + i + ": null");
                    }
                }
            }
            catch (IOException ioe)
            {
                Log.logWarning("Getting InputStream for application icon failed", ioe);
            }
        }

        return new LaunchAppInfo
               (ConfirmInstallation.getApplicationInfos(aBall),
                appIconInputStreams, suiteIconInputStream, suiteIconPath);
    }

    /**
     * Creates and starts a new thread for asking launch
     * application query from the user.
     */
    private void createLaunchAppQueryThread(InstallBall aBall)
    {
        final InstallBall ball = aBall;
        ball.iDialogOpen = true;
        new Thread(new Runnable()
        {
            public void run()
            {
                // Create and init LaunchAppinfo object.
                LaunchAppInfo launchAppInfo = createLaunchAppInfo(ball);
                // Display the query.
                boolean launchApp =
                    ball.getInstallerUi().launchAppQuery(launchAppInfo);

                // Close the jarFile and icon InputStreams.
                if (iJarFile != null)
                {
                    try
                    {
                        iJarFile.close(); // Closes also InputStreams
                        iJarFile = null;
                    }
                    catch (IOException ioe)
                    {
                        Log.logWarning("Closing icon InputStreams failed", ioe);
                    }
                }

                //if (ball.iSifRegistrator.getSifMode() > 0 && launchApp)
                //{
                //    ball.iSifRegistrator.launchAppView();
                //}
                //else
                if (ball.iCaptainMsgs && launchApp &&
                        launchAppInfo.getApplications() != null &&
                        launchAppInfo.getApplications().length > 0)
                {
                    int selection = launchAppInfo.getSelection();
                    Log.log("Launching application " + selection + ": " +
                            launchAppInfo.getApplications()[selection]
                            .getName());
                    ball.getCaptainService().startApp
                    (new Uid[] { launchAppInfo
                                 .getApplications()[selection]
                                 .getUid()
                               });
                }
                else
                {
                    Log.log("No application launch");
                }

                synchronized (ball)
                {
                    ball.iDialogOpen = false;
                    // Notify WaitForLaunchAppQuery step that
                    // we are finished with launch app query.
                    ball.notify();
                }
            }
        }, "LaunchAppQueryThread").start();
    }

    /**
     * Wait a moment if Nokia-MIDlet-Install-Commit-Wait atribute has been set.
     */
    private static void checkWaitAttribute(InstallBall aBall, String aWaitMsg)
    {
        String commitWaitEnabled = System.getProperty(
                                       "com.nokia.mj.impl.installer.commitwaitenabled");
        if (commitWaitEnabled != null &&
                commitWaitEnabled.equalsIgnoreCase("true"))
        {
            Log.log("commitWaitEnabled: " + commitWaitEnabled);
            String waitValue = aBall.getAttributeValue(
                                   "Nokia-MIDlet-Install-Commit-Wait");
            if (waitValue != null && waitValue.equalsIgnoreCase(aWaitMsg))
            {
                try
                {
                    int waitTime = 30; // secs
                    Log.log("Waiting " + waitTime + " secs " + aWaitMsg);
                    Thread.sleep(waitTime * 1000);
                }
                catch (InterruptedException ie)
                {
                }
            }
        }
    }
}