javamanager/javainstaller/installer/javasrc.s60/com/nokia/mj/impl/installer/applicationregistrator/SifNotifier.java
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 15 Sep 2010 12:05:25 +0300
branchRCL_3
changeset 77 7cee158cb8cd
parent 60 6c158198356e
child 83 26b2b12093af
permissions -rw-r--r--
Revision: v2.2.13 Kit: 201036

/*
* Copyright (c) 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.applicationregistrator;

import com.nokia.mj.impl.installer.ui.InstallerUi;
import com.nokia.mj.impl.installer.utils.InstallerException;
import com.nokia.mj.impl.installer.utils.Log;
import com.nokia.mj.impl.installer.utils.PropertyListener;
import com.nokia.mj.impl.installer.utils.PropertyProvider;

/**
 * Sends installation and uninstallation progress notifications
 * to platform's software installation framework.
 */
public final class SifNotifier
{
    /** Install operation. */
    public static final int OP_INSTALL = 1; // TSifOperationPhase::EInstalling
    /** Uninstall operation. */
    public static final int OP_UNINSTALL = 2; // TSifOperationPhase::EUninstalling
    /** Update operation. */
    public static final int OP_UPDATE = 3; // TSifOperationPhase::EUpgrading

    /** Indicates installation or uninstallation without
        specific suboperation. */
    public static final int SUB_OP_NO = 1; // TSifOperationSubPhase::ENoSubPhase
    /** OCSP phase during installation. */
    public static final int SUB_OP_OCSP = 2; // TSifOperationSubPhase::EOCSPCheck
    /** Download phase during installation. */
    public static final int SUB_OP_DOWNLOAD = 3; // TSifOperationSubPhase::EDownload
    /** Maximum progress notification value. */
    private static final int MAX_PROGRESS = 100;

    /** Operation being notified. */
    private int iOperation = 0;
    /** Suboperation during installation. */
    private int iSubOperation = 0;
    /** Global component id for the application. */
    private String iGlobalComponentId = null;
    /** Component name (i.e. suite name). */
    private String iComponentName = null;
    /** Application names. */
    private String[] iApplicationNames = null;
    /** Applications icons. */
    private String[] iApplicationIcons = null;
    /** Component initial size. */
    private int iComponentSize = 0;
    /** Icon dir. */
    private String iIconDir = null;
    /** Component icon. */
    private String iComponentIcon = null;

    /** Sending progress notifications is only allowed between start
     *  and end notifications. */
    private boolean iNotifyProgressAllowed = false;
    /**
     * Value of the last progress notification that has been sent with
     * SUB_OP_NO suboperation.
     */
    private int iLastProgressSent = 0;
    /** Current value of the last progress notification that has been sent. */
    private int iCurrentValue = 0;
    /** total value of the last progress notification that has been sent. */
    private int iTotalValue = 0;

    /** Native notifier object handle. */
    private int iHandle = 0;
    /** Native indicator object handle. */
    private int iIndicatorHandle = 0;
    /** InstallerUi handle. */
    private InstallerUi iInstallerUi = null;
    /** Provider for indicator status events. */
    private PropertyProvider iIndicatorStatusProvider = null;
    /** Indicator state. */
    private int iIndicatorState = -1;

    /*** ----------------------------- PUBLIC ------------------------------ */

    /**
     * Constructor.
     */
    public SifNotifier()
    {
        init();
    }

    /**
     * Set InstallerUi used when handling indicator.
     */
    public void setInstallerUi(InstallerUi aInstallerUi)
    {
        iInstallerUi = aInstallerUi;
    }

    /**
     * Activates and updates indicator which displays installation
     * progress to user while installer UI is hidden. The notifyStart
     * and notifyProgress methods must be called at least once before
     * calling this method.
     */
    public void activateIndicator()
    {
        if (iInstallerUi == null)
        {
            return;
        }

        if (iIndicatorHandle == 0)
        {
            int ret = _initIndicator();
            if (ret < 0)
            {
                Log.logError(
                    "Initializing SifNotifier indicator failed with code " +
                    ret);
            }
            else
            {
                Log.log("SifNotifier indicator created");
            }
            iIndicatorHandle = ret;
        }

        if (iIndicatorHandle == 0)
        {
            return;
        }

        int phase = 0;
        switch (iSubOperation)
        {
        case SUB_OP_OCSP: phase = 2; break; // TInstallingPhase::ECheckingCerts
        case SUB_OP_DOWNLOAD: phase = 1; break; // TInstallingPhase::EDownloading
        default: phase = 0; // TInstallingPhase::EInstalling
        }
        int progress = (iTotalValue == 0? 0: iCurrentValue*100/iTotalValue);
        updateIndicator(iComponentName, phase, progress);

        if (iIndicatorStatusProvider == null)
        {
            // Create PropertyListener which listens indicator status events
            // and unhides UI when necessary.
            final int indicatorCategory = 0x20022FC5; // sifuiinstallindicatorplugin
            final int indicatorKey = 0x2002E690; // /SifUiInstallIndicator/Status
            iIndicatorStatusProvider = new PropertyProvider();
            iIndicatorStatusProvider.subscribe(
                indicatorCategory, indicatorKey, new PropertyListener()
                {
                    public void valueChanged(int aCategory, int aKey, int aValue)
                    {
                        Log.log("SifNotifier indicator status " + aValue +
                                " (category=" + aCategory + ", key=" + aKey + ")");
                        iIndicatorState = aValue;
                        if (iIndicatorState == 0)
                        {
                            // Indicator has been closed, unhide the UI.
                            iInstallerUi.hide(false);
                        }
                    }
                });
            Log.log("SifNotifier indicator status provider subscribed");
        }
    }

    /**
     * Updates indicator which displays installation progress to user
     * while installer UI is hidden. The activateindicator method must
     * be called before calling this method.
     */
    public void updateIndicator(String aName, int aPhase, int aProgress)
    {
        if (iInstallerUi == null || iIndicatorHandle == 0)
        {
            return;
        }

        final String name = aName;
        final int phase = aPhase;
        final int progress = aProgress;
        iInstallerUi.syncExec(new Runnable()
        {
            // Indicator must be updated from UI thread.
            public void run()
            {
                int ret = _updateIndicator(
                    iIndicatorHandle, name, phase, progress);
                if (ret < 0)
                {
                    Log.logError(
                        "Updating SifNotifier indicator failed with code " +
                        ret);
                }
                else
                {
                    Log.log("SifNotifier indicator updated: " + name +
                            ", " + phase + ", " + progress + "%");
                }
            }
        });
    }

    /**
     * Deactivates indicator which displays installation
     * progress to user while installer UI is hidden.
     */
    public void deactivateIndicator()
    {
        if (iIndicatorStatusProvider != null)
        {
            iIndicatorStatusProvider.unsubscribe();
            iIndicatorStatusProvider = null;
            Log.log("SifNotifier indicator status provider unsubscribed");
        }

        if (iInstallerUi == null)
        {
            return;
        }

        iInstallerUi.syncExec(new Runnable()
        {
            // Indicator must be deactivated from UI thread.
            public void run()
            {
                if (iIndicatorHandle == 0)
                {
                    return;
                }
                int ret = _destroyIndicator(iIndicatorHandle, iIndicatorState);
                if (ret < 0)
                {
                    Log.logError(
                        "Destroying SifNotifier indicator failed with code " +
                        ret);
                }
                else
                {
                    Log.log("SifNotifier indicator destroyed");
                }
                iIndicatorHandle = 0;
            }
        });
    }

    /**
     * Returns true if SIF progress notifications are enabled, false otherwise.
     */
    public static boolean enabled()
    {
        return _sifNotifierEnabled();
    }

    /*
     * Notifies SIF that installation or uninstallation has started.
     *
     * @throws InstallerException in case an error occurs
     */
    public void notifyStart(
        int aOperation, String aGlobalComponentId, String aComponentName,
        String[] aApplicationNames, String[] aApplicationIcons,
        int aComponentSize, String aIconDir, String aComponentIcon)
    {
        iOperation = aOperation;
        iGlobalComponentId = aGlobalComponentId;
        iComponentName = aComponentName;
        iApplicationNames = aApplicationNames;
        iApplicationIcons = aApplicationIcons;
        iComponentSize = aComponentSize;
        iIconDir = aIconDir;
        iComponentIcon = aComponentIcon;

        checkHandle();
        int ret = _notifyStart(
                      iHandle, aOperation, aGlobalComponentId, aComponentName,
                      aApplicationNames, aApplicationIcons,
                      aComponentSize, aIconDir, aComponentIcon);
        if (ret < 0)
        {
            Log.log("Notifying SIF start failed with code " + ret +
                    ", " + getInfoString());
            InstallerException.internalError(
                "Notifying SIF start failed with code " + ret);
        }
        else
        {
            Log.log("SifNotifier.notifyStart: " + getInfoString());
        }
        iNotifyProgressAllowed = true;
    }

    /**
     * Notifies SIF that installation or uinstallation has ended.
     *
     * @throws InstallerException in case an error occurs
     */
    public void notifyEnd(
        int aErrCategory, int aErrCode, String aErrMsg, String aErrMsgDetails)
    {
        checkHandle();
        if (aErrCategory == 0 && iLastProgressSent < MAX_PROGRESS)
        {
            // Before sending end notification, update progress to max if
            // operation was successful and max progress notification has
            // not yet been sent.
            notifyProgress(SUB_OP_NO, MAX_PROGRESS, MAX_PROGRESS);
        }
        // No more progress notifications allowed.
        iNotifyProgressAllowed = false;
        int ret = _notifyEnd(
                      iHandle, iGlobalComponentId, aErrCategory, aErrCode,
                      aErrMsg, aErrMsgDetails);
        String logMsg =
            "ErrCategory: " + aErrCategory +
            ", ErrCode: " + aErrCode +
            ", ErrMsg: " + aErrMsg +
            ", ErrMsgDetails: " + aErrMsgDetails;
        if (ret < 0)
        {
            Log.log("Notifying SIF end failed with code " + ret +
                    ", " + getInfoString() + ", " + logMsg);
            InstallerException.internalError(
                "Notifying SIF end failed with code " + ret);
        }
        else
        {
            Log.log("SifNotifier.notifyEnd: " + logMsg);
        }
    }

    /**
     * Notifies SIF about installation or uninstallation progress.
     *
     * @throws InstallerException in case an error occurs
     */
    public void notifyProgress(int aSubOperation, int aCurrent, int aTotal)
    {
        if (!iNotifyProgressAllowed)
        {
            return;
        }

        iSubOperation = aSubOperation;
        iCurrentValue = aCurrent;
        iTotalValue = aTotal;
        if (iIndicatorHandle != 0)
        {
            // Call activateIndicator so that indicator gets updated.
            activateIndicator();
        }

        checkHandle();
        if (aSubOperation == SUB_OP_NO)
        {
            iLastProgressSent = aCurrent;
        }
        int ret = _notifyProgress(
                      iHandle, iGlobalComponentId, iOperation, aSubOperation,
                      aCurrent, aTotal);
        String logMsg =
            "SubOp: " + aSubOperation +
            ", Current: " + aCurrent +
            ", Total: " + aTotal;
        if (ret < 0)
        {
            Log.log("Notifying SIF progress failed with code " + ret +
                    ", " + getInfoString() + ", " + logMsg);
            InstallerException.internalError(
                "Notifying SIF progress failed with code " + ret);
        }
        else
        {
            Log.log("SifNotifier.notifyProgress: " + logMsg);
        }
    }

    /**
     * Destroys SifNotifier. This method releawse native resources and
     * must be called after SifNotifier is no longer used.
     *
     * @throws InstallerException in case an error occurs
     */
    public void destroy()
    {
        deactivateIndicator();
        checkHandle();
        int ret = _destroy(iHandle);
        if (ret < 0)
        {
            InstallerException.internalError(
                "Destroying SIF notifier failed with code " + ret);
        }
        else
        {
            Log.log("SifNotifier destroyed");
        }
        iHandle = 0;
    }

    /*** ----------------------------- PACKAGE ---------------------------- */

    /**
     * Initializes SifNotifier. This method must be called before any
     * other methods are called.
     *
     * @throws InstallerException if the notifier cannot be initialized
     */
    void init()
    {
        int ret = _init();
        if (ret < 0)
        {
            InstallerException.internalError(
                "Initializing SifNotifier failed with code " + ret);
        }
        else
        {
            Log.log("SifNotifier created");
        }
        iHandle = ret;
    }

    /*** ----------------------------- PRIVATE ---------------------------- */

    /**
     * Checks if notifier instance has been initialized.
     * @throws InstallerException if notifier has not been initialized
     */
    private void checkHandle()
    {
        if (iHandle == 0)
        {
            InstallerException.internalError(
                "SifNotifier.destroy: notifier has not been initialized");
        }
    }

    /**
     * Returns notification info string used in logging.
     */
    private String getInfoString()
    {
        StringBuffer buf = new StringBuffer();
        buf.append("Operation: ").append(iOperation);
        buf.append(", GlobalComponentId: ").append(iGlobalComponentId);
        buf.append(", ComponentName: ").append(iComponentName);
        if (iApplicationNames != null)
        {
            for (int i = 0; i < iApplicationNames.length; i++)
            {
                buf.append(", ApplicationName[").append(i).append("]: ")
                    .append(iApplicationNames[i]);
            }
        }
        if (iApplicationIcons != null)
        {
            for (int i = 0; i < iApplicationIcons.length; i++)
            {
                buf.append(", ApplicationIcon[").append(i).append("]: ")
                    .append(iApplicationIcons[i]);
            }
        }
        buf.append(", ComponentSize: ").append(iComponentSize);
        if (iIconDir != null)
        {
            buf.append(", IconDir: ").append(iIconDir);
        }
        if (iComponentIcon != null)
        {
            buf.append(", ComponentIcon: ").append(iComponentIcon);
        }
        return buf.toString();
    }

    /*** ----------------------------- NATIVE ----------------------------- */

    /**
     * Returns true if SIF progress notifications are enabled, false otherwise.
     */
    private static native boolean _sifNotifierEnabled();

    /**
     * Notifies SIF about installation/uinstallation start.
     *
     * @param aHandle
     * @param aOperation
     * @param aGlobalComponentId
     * @param aComponentName
     * @param aApplicationNames
     * @param aApplicationIcons
     * @param aComponentSize
     * @param aIconDir
     * @param aComponentIcon
     * @return Symbian error code (negative number) if operation fails,
     * otherwise 0
     */
    private static native int _notifyStart(
        int aHandle, int aOperation, String aGlobalComponentId,
        String aComponentName, String[] aApplicationNames,
        String[] aApplicationIcons, int aComponentSize,
        String aIconDir, String aComponentIcon);

    /**
     * Notifies SIF about installation/uinstallation completion.
     *
     * @param aHandle
     * @param aGlobalComponentId
     * @param aErrCategory
     * @param aErrCode
     * @param aErrMsg
     * @param aErrMsgDetails
     * @return Symbian error code (negative number) if operation fails,
     * otherwise 0
     */
    private static native int _notifyEnd(
        int aHandle, String aGlobalComponentId,
        int aErrCategory, int aErrCode,
        String aErrMsg, String aErrMsgDetails);

    /**
     * Notifies SIF about installation/uinstallation progress.
     *
     * @param aHandle
     * @param aGlobalComponentId
     * @param aOperation
     * @param aSubOperation
     * @param aCurrent
     * @param aTotal
     * @return Symbian error code (negative number) if operation fails,
     * otherwise 0
     */
    private static native int _notifyProgress(
        int aHandle, String aGlobalComponentId, int aOperation,
        int aSubOperation, int aCurrent, int aTotal);

    /**
     * Initializes SifNotifier. This method must be called before any
     * other methods are called.
     *
     * @return Symbian error code (negative number) if operation fails,
     * otherwise handle to the native side object
     */
    private static native int _init();

    /**
     * Cleans up SifNotifier. This method must be called after SifNotifier
     * is no longer used.
     *
     * @param aHandle
     * @return Symbian error code (negative number) if operation fails,
     * otherwise 0
     */
    private static native int _destroy(int aHandle);

    /**
     * Initializes SifNotifier indicator.
     *
     * @return Symbian error code (negative number) if operation fails,
     * otherwise handle to the native side object
     */
    private static native int _initIndicator();

    /**
     * Updates SifNotifier indicator.
     *
     * @param aHandle handle to indicator object
     * @param aName application name
     * @param aPhase operation phase
     * @param aProgress progress in percentage
     * @return Symbian error code (negative number) if operation fails,
     * otherwise handle to the native side object
     */
    private static native int _updateIndicator(
        int aHandle, String aName, int aPhase, int aProgress);

    /**
     * Destroys SifNotifier indicator.
     *
     * @param aHandle handle to indicator object
     * @param aState indicator state
     * @return Symbian error code (negative number) if operation fails,
     * otherwise 0
     */
    private static native int _destroyIndicator(int aHandle, int aState);

}