javamanager/javainstaller/installer/javasrc.s60/com/nokia/mj/impl/installer/applicationregistrator/SifRegistrator.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.mj.impl.installer.applicationregistrator;
       
    20 
       
    21 import com.nokia.mj.impl.installer.storagehandler.ApplicationInfo;
       
    22 import com.nokia.mj.impl.installer.storagehandler.SuiteInfo;
       
    23 import com.nokia.mj.impl.installer.utils.ComponentId;
       
    24 import com.nokia.mj.impl.installer.utils.InstallerException;
       
    25 import com.nokia.mj.impl.installer.utils.FileUtils;
       
    26 import com.nokia.mj.impl.installer.utils.Log;
       
    27 import com.nokia.mj.impl.installer.utils.PlatformUid;
       
    28 import com.nokia.mj.impl.rt.installer.ApplicationInfoImpl;
       
    29 import com.nokia.mj.impl.utils.Attribute;
       
    30 import com.nokia.mj.impl.utils.Uid;
       
    31 
       
    32 import java.util.Enumeration;
       
    33 import java.util.Hashtable;
       
    34 import java.util.Vector;
       
    35 
       
    36 /**
       
    37  * Registers (and unregisters) Java application to S60 platform's
       
    38  * software installation framework (USIF).
       
    39  */
       
    40 public final class SifRegistrator
       
    41 {
       
    42     /** Added application. Used with notifyAppChange() method. */
       
    43     public static final int APP_ADDED = 0;
       
    44     /** Removed application. Used with notifyAppChange() method. */
       
    45     public static final int APP_REMOVED = 1;
       
    46     /** Updated application. Used with notifyAppChange() method. */
       
    47     public static final int APP_UPDATED = 2;
       
    48 
       
    49     /** Native session handle. */
       
    50     private int iSessionHandle = 0;
       
    51 
       
    52     /*** ----------------------------- PUBLIC ------------------------------ */
       
    53 
       
    54     /**
       
    55      * Returns greater than zero if application registration to
       
    56      * software installation framework is enabled.
       
    57      */
       
    58     public static int getSifMode()
       
    59     {
       
    60         return _getUsifMode();
       
    61     }
       
    62 
       
    63     /**
       
    64      * Launches the application view. If launching application view
       
    65      * fails this method does not throw exception but produces an
       
    66      * error log entry.
       
    67      */
       
    68     public static void launchAppView()
       
    69     {
       
    70         int err = _launchAppView();
       
    71         if (err < 0)
       
    72         {
       
    73             Log.logError("Launching AppLib failed with code " + err);
       
    74         }
       
    75     }
       
    76 
       
    77     /**
       
    78      * Notifies system about added/updated/removed applications.
       
    79      * This method should be called only after the changes have been
       
    80      * committed.
       
    81      *
       
    82      * @param aAppUids application uids
       
    83      * @param aAppChange change type: APP_ADDED, APP_UPDATED, or APP_REMOVED
       
    84      * @throws InstallerException if notification fails
       
    85      */
       
    86     public static void notifyAppChange(Uid[] aAppUids, int aAppChange)
       
    87     {
       
    88         if (aAppUids == null || aAppUids.length == 0)
       
    89         {
       
    90             return;
       
    91         }
       
    92         int[] appUids = new int[aAppUids.length];
       
    93         for (int i = 0; i < appUids.length; i++)
       
    94         {
       
    95             appUids[i] = ((PlatformUid)aAppUids[i]).getIntValue();
       
    96         }
       
    97         int err = _notifyAppChange(appUids, aAppChange);
       
    98         if (err < 0)
       
    99         {
       
   100             InstallerException.internalError(
       
   101                 "Notifying app changes failed with code " + err);
       
   102         }
       
   103     }
       
   104 
       
   105     /**
       
   106      * Get component uid basing on component id.
       
   107      * This method can be called before session is created.
       
   108      *
       
   109      * @param aCid component id
       
   110      * @return uid for the component, or null if component is not found
       
   111      * @throws InstallerException if an error occurs
       
   112      */
       
   113     public static Uid getUid(int aCid)
       
   114     {
       
   115         // Use ComponentId to return int type value from native to java.
       
   116         ComponentId id = new ComponentId();
       
   117         int err = _getUid(aCid, id);
       
   118         if (err < 0)
       
   119         {
       
   120             InstallerException.internalError(
       
   121                 "Getting uid for cid " + aCid + " failed with code " + err);
       
   122         }
       
   123         Uid uid = null;
       
   124         if (id.getId() != 0)
       
   125         {
       
   126             uid = PlatformUid.createUid(id.getId());
       
   127         }
       
   128         return uid;
       
   129     }
       
   130 
       
   131     /**
       
   132      * Registers or unregisters Java software type to software
       
   133      * installation framework.
       
   134      *
       
   135      * @param aRegister true for registration, false for unregistration
       
   136      */
       
   137     public static void registerJavaSoftwareType(boolean aRegister)
       
   138     {
       
   139         String op = (aRegister? "Register": "Unregister");
       
   140         int err = _registerJavaSoftwareType(aRegister);
       
   141         if (err < 0)
       
   142         {
       
   143             InstallerException.internalError(
       
   144                 op + " Java software type failed with code " + err);
       
   145         }
       
   146         else
       
   147         {
       
   148             Log.log("SifRegistrator " + op + "ed Java software type");
       
   149         }
       
   150     }
       
   151 
       
   152     /**
       
   153      * Starts application registration session.
       
   154      * The registrations and unregistrations are done only
       
   155      * when commitSession is called.
       
   156      * If you want to discard the registrations and unregistrations
       
   157      * call rollbackSession.
       
   158      * Does nothing if session has already been successfully started
       
   159      * from this SifRegistrator instance.
       
   160      *
       
   161      * @param aTransaction true if also transaction for this session should
       
   162      * be opened, false otherwise
       
   163      * @throws InstallerException if the session cannot created
       
   164      * @see commitSession
       
   165      * @see rollbackSession
       
   166      */
       
   167     public void startSession(boolean aTransaction)
       
   168     {
       
   169         if (0 != iSessionHandle)
       
   170         {
       
   171             // Session has already been created, do nothing.
       
   172             Log.logWarning("SifRegistrator.startSession called although session is already open.");
       
   173             return;
       
   174         }
       
   175 
       
   176         // Native method writes error log and returns
       
   177         // negative Symbian error code if it fails.
       
   178         int ret = _startSession(aTransaction);
       
   179         if (ret < 0)
       
   180         {
       
   181             InstallerException.internalError(
       
   182                 "Creating session failed with code " + ret);
       
   183         }
       
   184         //Log.log("SifRegistrator session started");
       
   185         iSessionHandle = ret;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Registers Java application suite to S60 USIF.
       
   190      *
       
   191      * @param aSuiteInfo Information needed to register the application
       
   192      * @param aIsUpdate true in case of an update, false in case of a new
       
   193      * installation
       
   194      * @throws InstallerException if registration cannot done or
       
   195      *  startSession has not been called successfully
       
   196      * @see startSession
       
   197      * @see SuiteInfo
       
   198      */
       
   199     public void registerSuite(SuiteInfo aSuiteInfo, boolean aIsUpdate)
       
   200     {
       
   201         if (0 == iSessionHandle)
       
   202         {
       
   203             InstallerException.internalError("No valid SIF session.");
       
   204         }
       
   205         Log.log("SifRegistrator registering application suite " +
       
   206                 aSuiteInfo.getGlobalId());
       
   207 
       
   208         if (_getUsifMode() > 0)
       
   209         {
       
   210             // USIF Phase 2 registration.
       
   211             // Register suite as a component.
       
   212             registerComponent(aSuiteInfo, aIsUpdate);
       
   213             registerLocalizedComponentName(aSuiteInfo, -1);
       
   214             // Register applications within the component.
       
   215             Vector apps = aSuiteInfo.getApplications();
       
   216             for (int i = 0; i < apps.size(); i++)
       
   217             {
       
   218                 registerApplication(aSuiteInfo, i);
       
   219             }
       
   220         }
       
   221         else
       
   222         {
       
   223             // USIF Phase 1 registration.
       
   224             // Register each application in the suite.
       
   225             Vector apps = aSuiteInfo.getApplications();
       
   226             for (int i = 0; i < apps.size(); i++)
       
   227             {
       
   228                 registerComponent(aSuiteInfo, i, aIsUpdate);
       
   229                 registerLocalizedComponentName(aSuiteInfo, i);
       
   230             }
       
   231         }
       
   232         registerLocalizedProperties(aSuiteInfo);
       
   233     }
       
   234 
       
   235     /**
       
   236      * Unregisters Java application suite from S60 USIF.
       
   237      *
       
   238      * @param aSuiteInfo Information needed to unregister the application,
       
   239      * @throws InstallerException if unregistration cannot done or
       
   240      *  startSession has not been called successfully
       
   241      * @see startSession
       
   242      * @see SuiteInfo
       
   243      */
       
   244     public void unregisterSuite(SuiteInfo aSuiteInfo)
       
   245     {
       
   246         if (0 == iSessionHandle)
       
   247         {
       
   248             InstallerException.internalError("No valid SIF session.");
       
   249         }
       
   250         Log.log("SifRegistrator unregistering application suite " +
       
   251                 aSuiteInfo.getGlobalId());
       
   252 
       
   253         if (_getUsifMode() > 0)
       
   254         {
       
   255             // USIF Phase 2 unregistration.
       
   256             // Unregister suite as a component.
       
   257             unregisterComponent(aSuiteInfo);
       
   258         }
       
   259         else
       
   260         {
       
   261             // USIF Phase 1 unregistration.
       
   262             // Unregister each application in the suite.
       
   263             Vector apps = aSuiteInfo.getApplications();
       
   264             for (int i = 0; i < apps.size(); i++)
       
   265             {
       
   266                 unregisterComponent(aSuiteInfo, i);
       
   267             }
       
   268         }
       
   269     }
       
   270 
       
   271     /**
       
   272      * Commits the registrations and unregistrations.
       
   273      * Ends the current session if commit is successfull.
       
   274      * If commit fails the session is kept open so that
       
   275      * rollbackSession can be called.
       
   276      *
       
   277      * @throws InstallerException if session cannot be committed
       
   278      */
       
   279     public void commitSession()
       
   280     {
       
   281         if (0 == iSessionHandle)
       
   282         {
       
   283             InstallerException.internalError("No valid SIF session.");
       
   284         }
       
   285 
       
   286         int err = _commitSession(iSessionHandle);
       
   287         if (err < 0)
       
   288         {
       
   289             InstallerException.internalError("Commiting session failed with code " + err);
       
   290         }
       
   291         // Current session has been closed
       
   292         iSessionHandle = 0;
       
   293         //Log.log("SifRegistrator session committed");
       
   294     }
       
   295 
       
   296     /**
       
   297      * Rolls back the registrations and unregistrations.
       
   298      * Ends the current session.
       
   299      *
       
   300      * @throws InstallerException if session cannot be rolled back.
       
   301      */
       
   302     public void rollbackSession()
       
   303     {
       
   304         if (0 == iSessionHandle)
       
   305         {
       
   306             InstallerException.internalError("No valid SIF session.");
       
   307         }
       
   308 
       
   309         int err = _rollbackSession(iSessionHandle);
       
   310         // Session is closed always when rollback is called
       
   311         iSessionHandle = 0;
       
   312         if (err < 0)
       
   313         {
       
   314             InstallerException.internalError("Rolling back the session failed with code " + err);
       
   315         }
       
   316         //Log.log("SifRegistrator session rolled back");
       
   317     }
       
   318 
       
   319     /**
       
   320      * Closes the current session if it still open.
       
   321      * If registerComponent or unregisterComponent has been called,
       
   322      * commitSession or rollbackSession must be called instead of this method.
       
   323      */
       
   324     public void closeSession()
       
   325     {
       
   326         if (0 == iSessionHandle)
       
   327         {
       
   328             return;
       
   329         }
       
   330 
       
   331         _closeSession(iSessionHandle);
       
   332         // Current session has been closed
       
   333         iSessionHandle = 0;
       
   334         //Log.log("SifRegistrator session closed");
       
   335     }
       
   336 
       
   337     /**
       
   338      * Returns the component id of the application.
       
   339      *
       
   340      * @param aGlobalId the global id for the application.
       
   341      * @return the component id for the application, or null if the
       
   342      * application with given global id cannot be found.
       
   343      * @throws InstallerException if an error occurs
       
   344      */
       
   345     public ComponentId getComponentId(String aGlobalId)
       
   346     {
       
   347         if (0 == iSessionHandle)
       
   348         {
       
   349             InstallerException.internalError("No valid SIF session.");
       
   350         }
       
   351 
       
   352         ComponentId result = new ComponentId();
       
   353         int ret = _getComponentId(iSessionHandle, aGlobalId, result);
       
   354         if (-1 == ret)
       
   355         {
       
   356             // Symbian error code KErrNotFound means that the
       
   357             // application with given global id does not exist.
       
   358             result = null;
       
   359         }
       
   360         else if (ret < -1)
       
   361         {
       
   362             InstallerException.internalError(
       
   363                 "Getting component id for global id " + aGlobalId +
       
   364                 " failed with code " + ret);
       
   365         }
       
   366         return result;
       
   367     }
       
   368 
       
   369     /**
       
   370      * Returns the component id of the application.
       
   371      *
       
   372      * @param aAppUid the uid for the application.
       
   373      * @return the component id for the application, or null if the
       
   374      * application with given uid cannot be found.
       
   375      * @throws InstallerException if an error occurs
       
   376      */
       
   377     public ComponentId getComponentId(Uid aAppUid)
       
   378     {
       
   379         if (0 == iSessionHandle)
       
   380         {
       
   381             InstallerException.internalError("No valid SIF session.");
       
   382         }
       
   383 
       
   384         ComponentId result = new ComponentId();
       
   385         int ret = _getComponentIdForApp(
       
   386                       iSessionHandle, ((PlatformUid)aAppUid).getIntValue(), result);
       
   387         if (-1 == ret)
       
   388         {
       
   389             // Symbian error code KErrNotFound means that the
       
   390             // application with given uid does not exist.
       
   391             result = null;
       
   392         }
       
   393         else if (ret < -1)
       
   394         {
       
   395             InstallerException.internalError(
       
   396                 "Getting component id for uid " + aAppUid +
       
   397                 " failed with code " + ret);
       
   398         }
       
   399         return result;
       
   400     }
       
   401 
       
   402     /**
       
   403      * Writes information of the given application to JavaInstaller log.
       
   404      *
       
   405      * @param aGlobalId the global id for the application.
       
   406      */
       
   407     public void logComponent(String aGlobalId)
       
   408     {
       
   409         if (0 == iSessionHandle)
       
   410         {
       
   411             InstallerException.internalError("No valid SIF session.");
       
   412         }
       
   413 
       
   414         int ret = _logComponent(iSessionHandle, aGlobalId);
       
   415         if (ret < -1)
       
   416         {
       
   417             Log.logError("SifRegistrator logComponent failed with code " + ret);
       
   418         }
       
   419     }
       
   420 
       
   421     /*** ----------------------------- PACKAGE ---------------------------- */
       
   422     /*** ----------------------------- PRIVATE ---------------------------- */
       
   423 
       
   424     /**
       
   425      * Registers one Java application to S60 USIF as a component.
       
   426      * Used with USIF Phase 1.
       
   427      *
       
   428      * @param aSuiteInfo Information needed to register the application
       
   429      * @param aIndex index of the application in the suite
       
   430      * @param aIsUpdate true in case of an update, false in case of a new
       
   431      * installation
       
   432      * @throws InstallerException if registration cannot done or
       
   433      *  startSession has not been called successfully
       
   434      * @see startSession
       
   435      * @see SuiteInfo
       
   436      */
       
   437     private void registerComponent(
       
   438         SuiteInfo aSuiteInfo, int aIndex, boolean aIsUpdate)
       
   439     {
       
   440         String globalId = aSuiteInfo.getGlobalId(aIndex);
       
   441         if (globalId == null)
       
   442         {
       
   443             Log.logWarning("SifRegistrator: Application with index " + aIndex +
       
   444                            " not found from " + aSuiteInfo.getGlobalId());
       
   445             return;
       
   446         }
       
   447         ApplicationInfo appInfo =
       
   448             (ApplicationInfo)aSuiteInfo.getApplications().elementAt(aIndex);
       
   449         String suiteName = aSuiteInfo.getName();
       
   450         String vendor = aSuiteInfo.getVendor();
       
   451         String version = aSuiteInfo.getVersion().toString();
       
   452         String name = appInfo.getName();
       
   453         int uid = ((PlatformUid)appInfo.getUid()).getIntValue();
       
   454         String[] componentFiles = getComponentFiles(aSuiteInfo);
       
   455         long componentSize = aSuiteInfo.getInitialSize();
       
   456         String attrValue = aSuiteInfo.getAttributeValue("Nokia-MIDlet-Block-Uninstall");
       
   457         boolean isRemovable = !(attrValue != null && attrValue.equalsIgnoreCase("true"));
       
   458         boolean isDrmProtected = (aSuiteInfo.getContentInfo() == aSuiteInfo.CONTENT_INFO_DRM);
       
   459         boolean isOriginVerified = aSuiteInfo.isTrusted();
       
   460         String midletInfoUrl = aSuiteInfo.getAttributeValue("MIDlet-Info-URL");
       
   461         String midletDescription = aSuiteInfo.getAttributeValue("MIDlet-Description");
       
   462         String downloadUrl = aSuiteInfo.getAttributeValue("Nokia-MIDlet-Download-URL");
       
   463         ComponentId componentId = new ComponentId();
       
   464         int err = _registerComponent(
       
   465                       iSessionHandle, uid,
       
   466                       getScrString(suiteName), getScrString(vendor),
       
   467                       getScrString(version), getScrString(name),
       
   468                       getScrString(globalId), componentFiles,
       
   469                       componentSize, isRemovable, isDrmProtected,
       
   470                       isOriginVerified, aIsUpdate, aSuiteInfo.getMediaId(),
       
   471                       getScrString(midletInfoUrl),
       
   472                       getScrString(midletDescription),
       
   473                       getScrString(downloadUrl),
       
   474                       componentId);
       
   475         if (err < 0)
       
   476         {
       
   477             InstallerException.internalError(
       
   478                 "Registering component " + globalId +
       
   479                 " failed with code " + err);
       
   480         }
       
   481         else
       
   482         {
       
   483             appInfo.setComponentId(componentId);
       
   484             Log.log("SifRegistrator registered component " + globalId +
       
   485                     " with id " + componentId.getId());
       
   486         }
       
   487     }
       
   488 
       
   489     /**
       
   490      * Unregisters one Java application from being S60 USIF component.
       
   491      * Used with USIF Phase 1.
       
   492      *
       
   493      * @param aSuiteInfo Information needed to unregister the application,
       
   494      * @param aIndex index of the application in the suite
       
   495      * @throws InstallerException if unregistration cannot done or
       
   496      *  startSession has not been called successfully
       
   497      * @see startSession
       
   498      * @see SuiteInfo
       
   499      */
       
   500     private void unregisterComponent(SuiteInfo aSuiteInfo, int aIndex)
       
   501     {
       
   502         String globalId = aSuiteInfo.getGlobalId(aIndex);
       
   503         if (globalId == null)
       
   504         {
       
   505             Log.logWarning("SifRegistrator: Application with index " + aIndex +
       
   506                            " not found from " + aSuiteInfo.getGlobalId());
       
   507             return;
       
   508         }
       
   509         ComponentId componentId = getComponentId(globalId);
       
   510         if (componentId == null)
       
   511         {
       
   512             Log.logWarning(
       
   513                 "SifRegistrator unregistration failed, application " +
       
   514                 globalId + " does not exist");
       
   515             return;
       
   516         }
       
   517         // Save component id to ApplicationInfo.
       
   518         ApplicationInfo appInfo =
       
   519             (ApplicationInfo)aSuiteInfo.getApplications().elementAt(aIndex);
       
   520         appInfo.setComponentId(componentId);
       
   521         // Unregister application.
       
   522         int err = _unregisterComponent(iSessionHandle, componentId.getId());
       
   523         if (err < 0)
       
   524         {
       
   525             InstallerException.internalError(
       
   526                 "Unregistering component " + globalId +
       
   527                 " failed with code " + err);
       
   528         }
       
   529         else
       
   530         {
       
   531             Log.log("SifRegistrator unregistered component " + globalId +
       
   532                     " with id " + componentId.getId());
       
   533         }
       
   534     }
       
   535 
       
   536     /**
       
   537      * Registers Java application suite to S60 USIF as a component.
       
   538      * Used with USIF Phase 2.
       
   539      *
       
   540      * @param aSuiteInfo Suite information
       
   541      * @param aIsUpdate true in case of an update, false in case of a new
       
   542      * installation
       
   543      * @throws InstallerException if registration cannot done or
       
   544      *  startSession has not been called successfully
       
   545      * @see startSession
       
   546      * @see SuiteInfo
       
   547      */
       
   548     private void registerComponent(SuiteInfo aSuiteInfo, boolean aIsUpdate)
       
   549     {
       
   550         String globalId = aSuiteInfo.getGlobalId();
       
   551         String suiteName = aSuiteInfo.getName();
       
   552         String vendor = aSuiteInfo.getVendor();
       
   553         String version = aSuiteInfo.getVersion().toString();
       
   554         String name = null; // Set name to null so that suite name will be used.
       
   555         int uid = ((PlatformUid)aSuiteInfo.getUid()).getIntValue();
       
   556         String[] componentFiles = getComponentFiles(aSuiteInfo);
       
   557         long componentSize = aSuiteInfo.getInitialSize();
       
   558         String attrValue = aSuiteInfo.getAttributeValue("Nokia-MIDlet-Block-Uninstall");
       
   559         boolean isRemovable = !(attrValue != null && attrValue.equalsIgnoreCase("true"));
       
   560         boolean isDrmProtected = (aSuiteInfo.getContentInfo() == aSuiteInfo.CONTENT_INFO_DRM);
       
   561         boolean isOriginVerified = aSuiteInfo.isTrusted();
       
   562         String midletInfoUrl = aSuiteInfo.getAttributeValue("MIDlet-Info-URL");
       
   563         String midletDescription = aSuiteInfo.getAttributeValue("MIDlet-Description");
       
   564         String downloadUrl = aSuiteInfo.getAttributeValue("Nokia-MIDlet-Download-URL");
       
   565         ComponentId componentId = new ComponentId();
       
   566         int err = _registerComponent(
       
   567                       iSessionHandle, uid,
       
   568                       getScrString(suiteName), getScrString(vendor),
       
   569                       getScrString(version), getScrString(name),
       
   570                       getScrString(globalId), componentFiles,
       
   571                       componentSize, isRemovable, isDrmProtected,
       
   572                       isOriginVerified, aIsUpdate, aSuiteInfo.getMediaId(),
       
   573                       getScrString(midletInfoUrl),
       
   574                       getScrString(midletDescription),
       
   575                       getScrString(downloadUrl),
       
   576                       componentId);
       
   577         if (err < 0)
       
   578         {
       
   579             InstallerException.internalError(
       
   580                 "Registering component " + globalId +
       
   581                 " failed with code " + err);
       
   582         }
       
   583         else
       
   584         {
       
   585             aSuiteInfo.setComponentId(componentId);
       
   586             Log.log("SifRegistrator registered component " + globalId +
       
   587                     " with id " + componentId.getId());
       
   588         }
       
   589     }
       
   590 
       
   591     /**
       
   592      * Unregisters Java application suite from being S60 USIF component.
       
   593      * Used with USIF Phase 2.
       
   594      *
       
   595      * @param aSuiteInfo suite information
       
   596      * @throws InstallerException if unregistration cannot done or
       
   597      *  startSession has not been called successfully
       
   598      * @see startSession
       
   599      * @see SuiteInfo
       
   600      */
       
   601     private void unregisterComponent(SuiteInfo aSuiteInfo)
       
   602     {
       
   603         String globalId = aSuiteInfo.getGlobalId();
       
   604         ComponentId componentId = getComponentId(globalId);
       
   605         if (componentId == null)
       
   606         {
       
   607             Log.logWarning(
       
   608                 "SifRegistrator unregistration failed, application " +
       
   609                 globalId + " does not exist");
       
   610             return;
       
   611         }
       
   612         // Save component id to SuiteInfo.
       
   613         aSuiteInfo.setComponentId(componentId);
       
   614         // Unregister application.
       
   615         int err = _unregisterComponent(iSessionHandle, componentId.getId());
       
   616         if (err < 0)
       
   617         {
       
   618             InstallerException.internalError(
       
   619                 "Unregistering component " + globalId +
       
   620                 " failed with code " + err);
       
   621         }
       
   622         else
       
   623         {
       
   624             Log.log("SifRegistrator unregistered component " + globalId +
       
   625                     " with id " + componentId.getId());
       
   626         }
       
   627     }
       
   628 
       
   629     /**
       
   630      * Registers one Java application to S60 USIF as an S60 application.
       
   631      * The application is registered to component whose id is taken
       
   632      * from given SuiteInfo object. The SuiteInfo must already have
       
   633      * been registered to USIF as a component with registerComponent()
       
   634      * method before this method is called.
       
   635      * Used with USIF Phase 2.
       
   636      *
       
   637      * @param aSuiteInfo information needed to register the application
       
   638      * @param aIndex index of the application in the suite
       
   639      * @throws InstallerException if registration cannot done or
       
   640      *  startSession has not been called successfully
       
   641      * @see startSession
       
   642      * @see SuiteInfo
       
   643      */
       
   644     private void registerApplication(SuiteInfo aSuiteInfo, int aIndex)
       
   645     {
       
   646         int cid = aSuiteInfo.getComponentId().getId();
       
   647         ApplicationInfo appInfo =
       
   648             (ApplicationInfo)aSuiteInfo.getApplications().elementAt(aIndex);
       
   649         int appUid = ((PlatformUid)appInfo.getUid()).getIntValue();
       
   650         String appName = appInfo.getName();
       
   651         String appFilename = aSuiteInfo.getJarPath();
       
   652         String groupName = aSuiteInfo.getInstallationGroup();
       
   653         if (groupName == null)
       
   654         {
       
   655             groupName = ""; // default installation group
       
   656         }
       
   657         String iconFilename = aSuiteInfo.getRegisteredIconPath(aIndex);
       
   658         Log.log("SifRegistrator iconFilename " + aIndex + ": " + iconFilename);
       
   659         int numberOfIcons = 1;
       
   660         // Initalize localized names for the application.
       
   661         LocalizedName[] localizedNames = getLocalizedNames(
       
   662                                              aSuiteInfo, "Nokia-MIDlet-" + (aIndex+1) + "-");
       
   663         int[] languages = new int[localizedNames.length];
       
   664         String[] appNames = new String[localizedNames.length];
       
   665         for (int i = 0; i < localizedNames.length; i++)
       
   666         {
       
   667             languages[i] = localizedNames[i].getLanguage();
       
   668             appNames[i] = localizedNames[i].getName();
       
   669         }
       
   670         int err = _registerApplication(
       
   671                       iSessionHandle, cid, appUid, appName, appFilename, groupName,
       
   672                       iconFilename, numberOfIcons, languages, appNames);
       
   673         if (err < 0)
       
   674         {
       
   675             InstallerException.internalError(
       
   676                 "Registering application " + appUid + " to component " + cid +
       
   677                 " failed with code " + err);
       
   678         }
       
   679         else
       
   680         {
       
   681             Log.log("SifRegistrator registered application " + appUid +
       
   682                     " to component " + cid);
       
   683         }
       
   684     }
       
   685 
       
   686     private static String[] getComponentFiles(SuiteInfo aSuite)
       
   687     {
       
   688         Vector componentFiles = new Vector();
       
   689         String path = aSuite.getJadPath();
       
   690         if (path != null)
       
   691         {
       
   692             componentFiles.addElement(getScrString(path));
       
   693         }
       
   694         path = aSuite.getJarPath();
       
   695         if (path != null)
       
   696         {
       
   697             componentFiles.addElement(getScrString(path));
       
   698         }
       
   699         boolean addRootPath = true;
       
   700         int rootDrive = FileUtils.getDrive(aSuite.getRootDir());
       
   701         for (int i = 0; i < componentFiles.size(); i++)
       
   702         {
       
   703             if (FileUtils.getDrive((String)componentFiles.elementAt(i)) ==
       
   704                     rootDrive)
       
   705             {
       
   706                 // File from the root path drive already exists in
       
   707                 // component files vector, no need to add root path
       
   708                 // separately.
       
   709                 addRootPath = false;
       
   710                 break;
       
   711             }
       
   712         }
       
   713         if (addRootPath)
       
   714         {
       
   715             componentFiles.addElement(getScrString(aSuite.getRootDir()));
       
   716         }
       
   717         String[] result = new String[componentFiles.size()];
       
   718         componentFiles.copyInto(result);
       
   719         return result;
       
   720     }
       
   721 
       
   722     /**
       
   723      * Registers localized names for given application from given suite.
       
   724      * This method can be called only after registerComponent method has
       
   725      * been called.
       
   726      *
       
   727      * @param aSuite suite info
       
   728      * @param aIndex index of the application within the suite, if -1 then
       
   729      * localized names for the suite itself is registered
       
   730      */
       
   731     private void registerLocalizedComponentName(SuiteInfo aSuite, int aIndex)
       
   732     {
       
   733         LocalizedName[] localizedNames = null;
       
   734         int cid = 0;
       
   735         if (aIndex == -1)
       
   736         {
       
   737             if (aSuite.getComponentId() == null)
       
   738             {
       
   739                 Log.logWarning(
       
   740                     "SifRegistrator.registerLocalizedComponentName: cid not present in suite");
       
   741                 return;
       
   742             }
       
   743             cid = aSuite.getComponentId().getId();
       
   744             localizedNames = getLocalizedNames(aSuite, "Nokia-MIDlet-Name-");
       
   745         }
       
   746         else
       
   747         {
       
   748             ApplicationInfo app =
       
   749                 (ApplicationInfo)aSuite.getApplications().elementAt(aIndex);
       
   750             if (app.getComponentId() == null)
       
   751             {
       
   752                 Log.logWarning(
       
   753                     "SifRegistrator.registerLocalizedComponentName: cid not present in app");
       
   754                 return;
       
   755             }
       
   756             cid = app.getComponentId().getId();
       
   757             localizedNames = getLocalizedNames(
       
   758                                  aSuite, "Nokia-MIDlet-" + (aIndex+1) + "-");
       
   759         }
       
   760         for (int i = 0; i < localizedNames.length; i++)
       
   761         {
       
   762             int err = _registerLocalizedComponentName(
       
   763                           iSessionHandle, cid,
       
   764                           getScrString(localizedNames[i].getName()),
       
   765                           getScrString(aSuite.getVendor()),
       
   766                           localizedNames[i].getLanguage());
       
   767             if (err < 0)
       
   768             {
       
   769                 InstallerException.internalError(
       
   770                     "Adding localized name for component " + cid +
       
   771                     " failed with code " + err +
       
   772                     " (" + localizedNames[i] + ")");
       
   773             }
       
   774         }
       
   775     }
       
   776 
       
   777     /**
       
   778      * Registers localized property values for given suite.
       
   779      * This method can be called only after registerComponent
       
   780      * method has been called.
       
   781      *
       
   782      * @param aSuite suite info
       
   783      */
       
   784     private void registerLocalizedProperties(SuiteInfo aSuite)
       
   785     {
       
   786         if (aSuite.getComponentId() == null)
       
   787         {
       
   788             Log.logWarning(
       
   789                 "SifRegistrator.registerLocalizedProperties: cid not present in suite");
       
   790             return;
       
   791         }
       
   792         int cid = aSuite.getComponentId().getId();
       
   793         final int UNSPECIFIED_LOCALE = -1; // KUnspecifiedLocale
       
   794 
       
   795         // Register MIDlet-Delete-Confirm attribute values.
       
   796         final String attrName = "MIDlet-Delete-Confirm";
       
   797         String nonlocalizedAttrValue = aSuite.getAttributeValue(attrName);
       
   798         int err = _setLocalizedComponentProperty(
       
   799                       iSessionHandle, cid, getScrString(attrName),
       
   800                       getScrString(nonlocalizedAttrValue), UNSPECIFIED_LOCALE);
       
   801         if (err < 0)
       
   802         {
       
   803             InstallerException.internalError(
       
   804                 "Adding property " + attrName + " for component " + cid +
       
   805                 " failed with code " + err + " (" + nonlocalizedAttrValue + ")");
       
   806         }
       
   807         LocalizedName[] localizedAttrValues =
       
   808             getLocalizedNames(aSuite, attrName + "-");
       
   809         for (int i = 0; i < localizedAttrValues.length; i++)
       
   810         {
       
   811             err = _setLocalizedComponentProperty(
       
   812                       iSessionHandle, cid, getScrString(attrName),
       
   813                       getScrString(localizedAttrValues[i].getName()),
       
   814                       localizedAttrValues[i].getLanguage());
       
   815             if (err < 0)
       
   816             {
       
   817                 InstallerException.internalError(
       
   818                     "Adding localized property " + attrName +
       
   819                     " for component " + cid + " failed with code " + err +
       
   820                     " (" + localizedAttrValues[i] + ")");
       
   821             }
       
   822         }
       
   823 
       
   824         // Register Domain-Category property.
       
   825         ApplicationInfoImpl appInfoImpl = (ApplicationInfoImpl)
       
   826                                           com.nokia.mj.impl.rt.support.ApplicationInfo.getInstance();
       
   827         String domainCategory = appInfoImpl.getProtectionDomain();
       
   828         err = _setLocalizedComponentProperty(
       
   829                   iSessionHandle, cid, "Domain-Category",
       
   830                   domainCategory, UNSPECIFIED_LOCALE);
       
   831         if (err < 0)
       
   832         {
       
   833             InstallerException.internalError(
       
   834                 "Adding property Domain-Category value " + domainCategory +
       
   835                 " for component " + cid + " failed with code " + err);
       
   836         }
       
   837     }
       
   838 
       
   839     /**
       
   840      * Returns array of localized names from the specified
       
   841      * attributes of given suite. Assumes that aAttrPrefix
       
   842      * is an attribute name prefix that is followed by locale.
       
   843      * If the same locale is found more than once, localized
       
   844      * name for only the last occurrence is returned.
       
   845      */
       
   846     private LocalizedName[] getLocalizedNames(
       
   847         SuiteInfo aSuite, String aAttrPrefix)
       
   848     {
       
   849         Hashtable localizedNames = new Hashtable();
       
   850         Enumeration e = aSuite.getAttributes().elements();
       
   851         while (e.hasMoreElements())
       
   852         {
       
   853             Attribute attr = (Attribute)e.nextElement();
       
   854             String name = attr.getName();
       
   855             if (name.startsWith(aAttrPrefix))
       
   856             {
       
   857                 String locale = name.substring(aAttrPrefix.length());
       
   858                 if (isValidLocale(locale))
       
   859                 {
       
   860                     LocalizedName localizedName =
       
   861                         new LocalizedName(attr.getValue(), locale);
       
   862                     if (localizedName.getLanguage() == -1)
       
   863                     {
       
   864                         Log.logWarning(
       
   865                             "SifRegistrator ignored unknown locale: " +
       
   866                             name + ": " + localizedName);
       
   867                     }
       
   868                     else
       
   869                     {
       
   870                         Log.log("SifRegistrator found localized text " +
       
   871                                 name + ": " + localizedName);
       
   872                         localizedNames.put(
       
   873                             new Integer(localizedName.getLanguage()),
       
   874                             localizedName);
       
   875                     }
       
   876                 }
       
   877             }
       
   878         }
       
   879         LocalizedName[] result = new LocalizedName[localizedNames.size()];
       
   880         e = localizedNames.elements();
       
   881         for (int i = 0; e.hasMoreElements(); i++)
       
   882         {
       
   883             result[i] = (LocalizedName)e.nextElement();
       
   884         }
       
   885         return result;
       
   886     }
       
   887 
       
   888     /**
       
   889      * Returns true if given locale is a valid one. Valid locales
       
   890      * use two letter ISO language and optionally country codes.
       
   891      */
       
   892     private boolean isValidLocale(String aLocale)
       
   893     {
       
   894         boolean result = false;
       
   895         if (aLocale.length() == 2)
       
   896         {
       
   897             // Assume that locale has only language code.
       
   898             result = true;
       
   899         }
       
   900         if (aLocale.length() == 5)
       
   901         {
       
   902             // Assume that locale has language and country codes.
       
   903             char separator = aLocale.charAt(2);
       
   904             if (separator == '-' || separator == '_')
       
   905             {
       
   906                 result = true;
       
   907             }
       
   908         }
       
   909         return result;
       
   910     }
       
   911 
       
   912     /**
       
   913      * Returns a string which can be stored to S60 SCR. This method ensures
       
   914      * that the length of the returned string does not exceed the maximum
       
   915      * length limit set by SCR (512 characters).
       
   916      */
       
   917     private static String getScrString(String aStr)
       
   918     {
       
   919         final int maxLen = 512;
       
   920         if (aStr != null && aStr.length() > maxLen)
       
   921         {
       
   922             return aStr.substring(0, maxLen);
       
   923         }
       
   924         return aStr;
       
   925     }
       
   926 
       
   927     /*** ----------------------------- NATIVE ----------------------------- */
       
   928 
       
   929     /**
       
   930      * Notifies system about added/updated/removed applications.
       
   931      * This method should be called only after the changes have been
       
   932      * committed.
       
   933      *
       
   934      * @param aAppUids application uids
       
   935      * @param aAppChange change type: APP_ADDED, APP_UPDATED, or APP_REMOVED
       
   936      * @return 0 or Symbian error code (negative number)
       
   937      */
       
   938     private static native int _notifyAppChange(int[] aAppUids, int aAppChange);
       
   939 
       
   940     /**
       
   941      * Launches the applications view.
       
   942      *
       
   943      * @return 0 or Symbian error code (negative number)
       
   944      */
       
   945     private static native int _launchAppView();
       
   946 
       
   947     /**
       
   948      * Registers Java software type to software installation framework.
       
   949      *
       
   950      * @param aRegister true for registration, false for unregistration
       
   951      * @return 0 or Symbian error code (negative number)
       
   952      */
       
   953     private static native int _registerJavaSoftwareType(boolean aRegister);
       
   954 
       
   955     /**
       
   956      * Starts native application registration session.
       
   957      *
       
   958      * @param aTransaction true if also transaction for this session should
       
   959      * be opened, false otherwise
       
   960      * @return native session handle or Symbian error code (negative number)
       
   961      */
       
   962     private static native int _startSession(boolean aTransaction);
       
   963 
       
   964     /**
       
   965      * Commits native application registration session.
       
   966      * If commit succeeds the native session is closed.
       
   967      *
       
   968      * @param aSessionHandle
       
   969      * @param aSynchronous if true, makes synchronous commit
       
   970      * @return 0 or Symbian error code (negative number)
       
   971      */
       
   972     private static native int _commitSession(int aSessionHandle);
       
   973 
       
   974     /**
       
   975      * Rolls back and closes native application registration session.
       
   976      *
       
   977      * @param aSessionHandle
       
   978      * @return 0 or Symbian error code (negative number)
       
   979      */
       
   980     private static native int _rollbackSession(int aSessionHandle);
       
   981 
       
   982     /**
       
   983      * Closes native application registration session.
       
   984      *
       
   985      * @param aSessionHandle the session to be closed
       
   986      */
       
   987     private static native void _closeSession(int aSessionHandle);
       
   988 
       
   989     /**
       
   990      * Registers Java application to S60 USIF as a component.
       
   991      *
       
   992      * @param aSessionHandle
       
   993      * @param aUid
       
   994      * @param aSuiteName
       
   995      * @param aVendor
       
   996      * @param aVersion
       
   997      * @param aName
       
   998      * @param aGlobalId
       
   999      * @param aComponentFiles
       
  1000      * @param aComponentSize
       
  1001      * @param aIsRemovable
       
  1002      * @param aIsDrmProtected
       
  1003      * @param aIsOriginVerified
       
  1004      * @param aIsUpdate
       
  1005      * @param aMediaId
       
  1006      * @param aMidletInfoUrl
       
  1007      * @param aMidletDescription
       
  1008      * @param aDownloadUrl
       
  1009      * @param aComponentId upon successful execution contains the
       
  1010      * component id for the registered component
       
  1011      * @return 0 if registration succeeded or Symbian error code
       
  1012      */
       
  1013     private static native int _registerComponent(
       
  1014         int aSessionHandle, int aUid, String aSuiteName, String aVendor,
       
  1015         String aVersion, String aName, String aGlobalId,
       
  1016         String[] aComponentFiles, long aComponentSize,
       
  1017         boolean aIsRemovable, boolean aIsDrmProtected,
       
  1018         boolean aIsOriginVerified, boolean aIsUpdate, int aMediaId,
       
  1019         String aMidletInfoUrl, String aMidletDescription, String aDownloadUrl,
       
  1020         ComponentId aComponentId);
       
  1021 
       
  1022     /**
       
  1023      * Unregisters Java application from S60 USIF.
       
  1024      *
       
  1025      * @param aSessionHandle
       
  1026      * @param aComponentId The component id of the application
       
  1027      * @return 0 if unregistration succeeded or Symbian error code
       
  1028      */
       
  1029     private static native int _unregisterComponent(
       
  1030         int aSessionHandle, int aComponentId);
       
  1031 
       
  1032     /**
       
  1033      * Registers Java application to S60 USIF as an application
       
  1034      * inside specified component.
       
  1035      *
       
  1036      * @param aSessionHandle
       
  1037      * @param aCid
       
  1038      * @param aAppUid
       
  1039      * @param aAppName
       
  1040      * @param aAppFilename
       
  1041      * @param aGroupName
       
  1042      * @param aIconFilename
       
  1043      * @param aNumberOfIcons
       
  1044      * @param aLanguages
       
  1045      * @param aAppNames
       
  1046      * @return 0 if registration succeeded or Symbian error code
       
  1047      */
       
  1048     private static native int _registerApplication(
       
  1049         int aSessionHandle, int aCid, int aAppUid, String aAppName,
       
  1050         String aAppFilename, String aGroupName, String aIconFilename,
       
  1051         int aNumberOfIcons, int[] aLanguages, String[] aAppNames);
       
  1052 
       
  1053     /**
       
  1054      * Registers localized name and vendor for specified component.
       
  1055      *
       
  1056      * @param aSessionHandle
       
  1057      * @param aCid component id
       
  1058      * @param aName localized component name
       
  1059      * @param aVendor localized component vendor (can be null)
       
  1060      * @param aLanguage S60 language code
       
  1061      * @return 0 if unregistration succeeded or Symbian error code
       
  1062      */
       
  1063     private static native int _registerLocalizedComponentName(
       
  1064         int aSessionHandle, int aCid, String aName, String aVendor, int aLanguage);
       
  1065 
       
  1066     /**
       
  1067      * Sets localized property value for specified component.
       
  1068      *
       
  1069      * @param aSessionHandle
       
  1070      * @param aCid component id
       
  1071      * @param aName property name
       
  1072      * @param aValue localized property value
       
  1073      * @param aLanguage S60 language code
       
  1074      * @return 0 if unregistration succeeded or Symbian error code
       
  1075      */
       
  1076     private static native int _setLocalizedComponentProperty(
       
  1077         int aSessionHandle, int aCid, String aName, String aValue, int aLanguage);
       
  1078 
       
  1079     /**
       
  1080      * Returns the component id of the application.
       
  1081      *
       
  1082      * @param aSessionHandle
       
  1083      * @param aGlobalId
       
  1084      * @param aComponentId contains component id after successful function call
       
  1085      * @return Symbian error code (negative number) if fails, otherwise 0
       
  1086      */
       
  1087     private static native int _getComponentId(
       
  1088         int aSessionHandle, String aGlobalId, ComponentId aComponentId);
       
  1089 
       
  1090     /**
       
  1091      * Returns the component id of the application.
       
  1092      *
       
  1093      * @param aSessionHandle
       
  1094      * @param aAppUid
       
  1095      * @param aComponentId contains component id after successful function call
       
  1096      * @return Symbian error code (negative number) if fails, otherwise 0
       
  1097      */
       
  1098     private static native int _getComponentIdForApp(
       
  1099         int aSessionHandle, int aAppUid, ComponentId aComponentId);
       
  1100 
       
  1101     /**
       
  1102      * Returns the uid of the component.
       
  1103      *
       
  1104      * @param aSessionHandle
       
  1105      * @param aCid component id
       
  1106      * @param aUid contains uid after successful function call
       
  1107      * @return Symbian error code (negative number) if fails, otherwise 0
       
  1108      */
       
  1109     private static native int _getUid(int aCid, ComponentId aUid);
       
  1110 
       
  1111     /**
       
  1112      * Writes information of the given application to JavaInstaller log.
       
  1113      *
       
  1114      * @param aSessionHandle
       
  1115      * @param aGlobalId the global id for the application
       
  1116      * @return Symbian error code (negative number) if fails, otherwise 0
       
  1117      */
       
  1118     private static native int _logComponent(
       
  1119         int aSessionHandle, String aGlobalId);
       
  1120 
       
  1121     /**
       
  1122      * Checks if USIF is enabled.
       
  1123      *
       
  1124      * @return 1 if application data should be registered to USIF, 0 otherwise
       
  1125      */
       
  1126     private static native int _getUsifMode();
       
  1127 }