diff -r 000000000000 -r dd21522fd290 webengine/widgetinstaller/Src/WidgetInstaller.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/widgetinstaller/Src/WidgetInstaller.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,1018 @@ +/* +* Copyright (c) 2006, 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: This file contains the header file of the CMidletUI class. +* +* This class implements the ECom SWInstUIPluginAPI interface +* for midlet installation. +* +* +*/ + +#include +#include +#include + +#include "WidgetInstaller.h" +#include "WidgetConfigHandler.h" // info.plist parser +#include "WidgetRegistrationManager.h" // interface to "shell" +#include "IconConverter.h" + +// CONSTANTS +_LIT( KInfoPList,"Info.plist" ); +_LIT( KIconFile, "Icon.png" ); +_LIT( KMBMExt, ".mbm"); +_LIT( KLprojExt, ".lproj" ); +_LIT( KInfoPlistStrings, "InfoPlist.strings" ); + +// TODO MW has a hard dependency to APP domain. Not very good... +// TODO Hard-coded UID. +_LIT( KWidgetAppDir, "\\private\\10282822\\" ); +_LIT( KBackSlash, "\\" ); +// todo: other keystring.dat for preference +_LIT(KWidgetPref, "prefs.dat"); + + +// =========================== MEMBER FUNCTIONS =============================== + + +// ============================================================================ +// CWidgetInstaller::NewL() +// two-phase constructor +// +// @since 3.1 +// @return pointer to CWidgetInstaller +// ============================================================================ +// +EXPORT_C CWidgetInstaller* CWidgetInstaller::NewL() + { + CWidgetInstaller* self + = new (ELeave) CWidgetInstaller(); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ============================================================================ +// CWidgetInstaller::CWidgetInstaller() +// C++ constructor +// +// @since 3.1 +// ============================================================================ +// +CWidgetInstaller::CWidgetInstaller() + : iPropertyValues( EWidgetPropertyIdCount ) + { + } + +// ============================================================================ +// CWidgetInstaller::ConstructL() +// Symbian second phase constructor +// +// @since 3.1 +// ============================================================================ +// +void CWidgetInstaller::ConstructL() + { + User::LeaveIfError( iRfs.Connect() ); + User::LeaveIfError( iRfs.ShareProtected() ); + iFileMgr = CFileMan::NewL( iRfs ); + + iAppManager = CWidgetRegistrationManager::NewL( iRfs ); + iWidgetConfigHandler = CWidgetConfigHandler::NewL(); + + // delay registry connect because registry is a client and that + // produces a circular dependency + iServerConnected = EFalse; + + // empty values + for ( TInt i( 0 ); i < EWidgetPropertyIdCount; ++i ) + { + CWidgetPropertyValue* value = CWidgetPropertyValue::NewL(); + User::LeaveIfError( iPropertyValues.Insert( value, i ) ); + } + *(iPropertyValues[EWidgetPropertyListVersion]) = WIDGETPROPERTYLISTVERSION; + +#ifdef _DEBUG + _LIT(KDir, "WidgetBUR"); + _LIT(KFile, "WidgetBURInstaller.log"); + TInt err( 0 ); + + err = iFileLogger.Connect(); + if ( err == KErrNone ) + { + iFileLogger.CreateLog( KDir(), KFile(), EFileLoggingModeOverwrite ); + iCanLog = ETrue; + } +#endif + } + +// ============================================================================ +// CWidgetInstaller::~CWidgetInstaller() +// destructor +// +// @since 3.1 +// ============================================================================ +// +CWidgetInstaller::~CWidgetInstaller() + { + TInt i = 0; + for ( ; i < EWidgetPropertyIdCount; ++i ) + { + delete iPropertyValues[i]; + } + iPropertyValues.Close(); + + delete iFileMgr; + iRfs.Close(); + + delete iWidgetConfigHandler; + delete iAppManager; + + if ( iServerConnected ) + { + iRegistry.Disconnect(); + } +#ifdef _DEBUG + iFileLogger.Close(); +#endif + } + +// ============================================================================ +// CWidgetInstaller::InstallL() +// NORMAL INSTALL STEPS: +// 2. get metadata file (e.g. Info.plist) and parse it +// 3. if needed, replace identically named existing widget) +// 4. do free space check +// 5. if replacing existing widget then move currently installed files +// to backup for possible restore on install error +// +// @since 3.1 +// ============================================================================ +// +EXPORT_C void CWidgetInstaller::InstallL( + TDesC& aRestoreDir ) + { + if ( EFalse == iServerConnected ) + { + User::LeaveIfError( iRegistry.Connect() ); + iServerConnected = ETrue; + } + + // The bool will be flase until doing something that + // needs to be cleaned up on error/cancel. + iOverwriting = EFalse; + + TRAPD( error, + { + // do initial bundle processing (parse and validate, total size, + // check if replacing existing widget with same bundle ID, etc.) + // + // this step doesn't do anything that would need to be undone + TBool replaceExisting = PreprocessWidgetBundleL( aRestoreDir ); + SetDriveAndCheckSpaceL(); + + if ( replaceExisting ) + { + BackupL(); // nothing need be undone if backup leaves + } + } + ); // TRAPD + if ( error == KErrNone ) + { + ProcessRestoreDirL( aRestoreDir ); + } + else if ( error == KErrAlreadyExists ) + { + // max number of uid reached, to avoid SBE undo previous widget restore, don't leave with error + return; + } + else + { + User::Leave( error ); + } + } + +// ============================================================================ +// CWidgetInstaller::SearchWidgetRootL +// +// @since 3.2 +// ============================================================================ +// +TInt CWidgetInstaller::SearchWidgetRootL( const TDesC& aDir, TFileName& aFoundName ) + { + CDir* entryList = NULL; + TBool found = EFalse; + RFile rFile; + + // aDir = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\" + TInt err = iRfs.GetDir( aDir, KEntryAttMatchMask, EDirsFirst, entryList ); + if ( err == KErrNone ) + { + CleanupStack::PushL(entryList); + + // check for directory entries + TInt cnt = entryList->Count(); + for (TInt i=0; iReset(); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // find the top-level directory under which to get metadata + // aRestoreDir = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID" + // tempFile = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\" + // iBundleRootName = "WeatherBug.wdgt" + TFileName tempFile( aRestoreDir ); + tempFile.Append( KBackSlash ); + // searching for a directory which contains info.plist (under tempFile), + // rather than return the first directory found. + TInt foundRoot = SearchWidgetRootL( tempFile, iBundleRootName ); + if( !foundRoot ) + { + User::Leave( KErrNotSupported ); + } + + // root dir in widget bundle (not install root) of WidgetBackupRestore + // e.g. bundleRoot = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\WeatherBug.wdgt\" + TFileName bundleRoot( tempFile ); + bundleRoot.Append( iBundleRootName ); + bundleRoot.Append( KBackSlash ); + + TInt64 bundleRootSize = GetDirSizeL( bundleRoot ); + if ( 0 == bundleRootSize ) + { + User::Leave( KErrNotSupported ); + } + *(iPropertyValues[EFileSize]) = bundleRootSize; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // metadata file: "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\WeatherBug.wdgt\Info.plist" + tempFile.Copy( bundleRoot ); + tempFile.Append( KInfoPList ); + TInt err = rFile.Open( iRfs, tempFile, EFileRead ); + if ( KErrNone != err ) + { + // missing metadata file + User::Leave( KErrNotSupported ); + } + CleanupClosePushL( rFile ); + + TInt size = 0; + rFile.Size( size ); + HBufC8* buffer = HBufC8::NewLC( size ); + TPtr8 bufferPtr( buffer->Des() ); + User::LeaveIfError( rFile.Read( bufferPtr ) ); + + // METADATA PARSE + iWidgetConfigHandler->ParseValidateBundleMetadataL( + bufferPtr, iPropertyValues, iRfs ); + + CleanupStack::PopAndDestroy( 2, &rFile ); // rFile, buffer + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // EXISTING WIDGET? + if( iRegistry.WidgetExistsL( *(iPropertyValues[EBundleIdentifier]) ) ) + { + // replacement for currently installed widget + *(iPropertyValues[EUid]) = iRegistry.GetWidgetUidL( + *(iPropertyValues[EBundleIdentifier])); + found = ETrue; + // get original install dir from registry in case user + // decides to "overrite" to another memory location + // e.g. iOriginalDir = "\private\[WidgetUIUid]\bundleID\" + iRegistry.GetWidgetPath( TUid::Uid( *(iPropertyValues[EUid]) ), + iOriginalDir ); + } + else + { + // new widget, get an unused UID for this widget + TDriveUnit phoneMemDriveUnit( EDriveC ); + const TDesC& drive = phoneMemDriveUnit.Name(); + *(iPropertyValues[EUid]) = iRegistry.GetAvailableUidL(drive[0]).iUid; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // see if main.html exists + // main.html file: "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\WeatherBug.wdgt\YahooTraffic.html" + tempFile.Copy( bundleRoot ); + tempFile.Append( *(iPropertyValues[EMainHTML]) ); + if( !BaflUtils::FileExists( iRfs, tempFile ) ) + { + User::Leave( KErrCorrupt ); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // infoLoc file: "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\WeatherBug.wdgt\en.lproj\InfoPlist.strings" + TBuf<32> lproj; + iRegistry.GetLprojName( lproj ); // e.g. "en", "fr", "zh_Hans" ... + TFileName infoLocFile( bundleRoot ); + infoLocFile.Append( lproj ); + infoLocFile.Append( KLprojExt ); + infoLocFile.Append( KBackSlash ); + infoLocFile.Append( KInfoPlistStrings ); + + err = rFile.Open( iRfs, infoLocFile, EFileRead ); + + CleanupClosePushL( rFile ); + if ( err == KErrNone ) + { + TInt size = 0; + rFile.Size( size ); + HBufC8* buffer = HBufC8::NewLC( size ); + TPtr8 bufferPtr( buffer->Des() ); + err = rFile.Read( bufferPtr ); + User::LeaveIfError( err ); + + // parse the l10n file and localize the bundle display name + iWidgetConfigHandler->ParseInfoLocL( + bufferPtr, iRfs, *(iPropertyValues[EBundleDisplayName]) ); + CleanupStack::PopAndDestroy( buffer ); // buffer + } + CleanupStack::PopAndDestroy( &rFile ); // rFile + + return found; + } + +void CWidgetInstaller::ProcessRestoreDirL( TDesC& aRestoreDir ) + { + TInt err = KErrNone; + HBufC* newDir( HBufC::NewLC( KMaxFileName ) ); + HBufC* tmpDir( HBufC::NewLC( KMaxFileName ) ); + ////////////////////////////////////////////////////////////////////////////////////////////////// + // widgetAppDir = "\private\[WidgetUIUid]\" + // If the path is missing create it. + if ( !BaflUtils::FolderExists( iRfs, KWidgetAppDir ) ) + { + User::LeaveIfError( iRfs.MkDir( KWidgetAppDir ) ); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // newDir = "\private\[WidgetUIUid]\bundleID\" + *newDir = *(iPropertyValues[EBasePath]); + // oldDir = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID" + *tmpDir = aRestoreDir; + // oldDir = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\" + tmpDir->Des().Append( KBackSlash ); + + TInt renameError = iRfs.Rename( *tmpDir, *newDir ); + if (renameError) + { + // copy if different drive or KErrAlreadyExists + CFileMan* fileManager = CFileMan::NewL( iRfs ); + CleanupStack::PushL( fileManager ); + User::LeaveIfError( fileManager->Copy( *tmpDir, *newDir, CFileMan::ERecurse ) ); + User::LeaveIfError( fileManager->Attribs(*newDir, KEntryAttNormal, KEntryAttReadOnly, + TTime(0), CFileMan::ERecurse) ); + CleanupStack::PopAndDestroy( fileManager ); // fileMananger + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // e.g. bundleRootWithDrive = "C:\private\[WidgetUIUid]\bundleID\WeatherBug.wdgt\" + // e.g. iBundleRootName = "WeatherBug.wdgt" + TFileName bundleRootWithDrive( *newDir ); + bundleRootWithDrive.Append( iBundleRootName ); + bundleRootWithDrive.Append( KBackSlash ); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // update MainHTML info + TFileName mainHtml( bundleRootWithDrive ); + mainHtml.Append( *(iPropertyValues[EMainHTML]) ); + *(iPropertyValues[EMainHTML]) = mainHtml; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // parse the Icon.png file + // e.g. iconPath = "C:\private\[WidgetUIUid]\bundleID\WeatherBug.wdgt\" + TFileName iconPath( bundleRootWithDrive ); + TFileName iconFile( iconPath ); + iconFile.Append( KIconFile ); + if ( BaflUtils::FileExists( iRfs, iconFile ) ) + { + *(iPropertyValues[EIconPath]) = iconPath; + + // scan the bundleRootWithDrive directory + TFileName oldMbmIconTemp( KNullDesC ); + TBool mbmIconFound = SearchByExtL( bundleRootWithDrive, EDirsLast | EDescending, KMBMExt, oldMbmIconTemp ); + // skip converting to .mbm file, simply rename oldUid.mbm to newUid.mbm + // where oldUid comes from backup widget, + // newUid comes from widget registration or reuse of existing widget uid + if( mbmIconFound ) + { + TUid uid = TUid::Uid( *(iPropertyValues[EUid]) ); + // e.g. newMbmIcon = "C:\private\[WidgetUIUid]\bundleID\WeatherBug.wdgt\[newUid].mbm" + TFileName newMbmIcon( iconPath ); + newMbmIcon.Append( uid.Name() ); + newMbmIcon.Append( KMBMExt() ); + + // e.g. oldMbmIcon = "C:\private\[WidgetUIUid]\bundleID\WeatherBug.wdgt\[oldUid].mbm" + TFileName oldMbmIcon( iconPath ); + oldMbmIcon.Append( oldMbmIconTemp ); + err = iRfs.Rename( oldMbmIcon, newMbmIcon ); + // it's ok that oldMbm and newMbm share the same uid + if( err != KErrNone && err != KErrAlreadyExists ) + { + User::Leave( err ); + } + } + else + { + // This case is specific to the WidgetPreInstaller. + // Once the mbm file can be generated by the script this won't be needed. + // Create the mbm file from the icon file + TUid uid = TUid::Uid( *(iPropertyValues[EUid]) ); + ConvertIconL(uid, iconPath); + } + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // delete "\private\[WidgetUIUid]\bundleID\prefs.dat" + TFileName widgetPref( *newDir ); + widgetPref.Append(KWidgetPref); + err = iRfs.Delete( widgetPref ); + // it's ok not to have pref.dat + if( err != KErrNone && err != KErrNotFound ) + { + User::Leave( err ); + } + + CleanupStack::PopAndDestroy( 2, newDir ); + ////////////////////////////////////////////////////////////////////////////////////////////////// + FinishInstallL( KErrNone ); + } + +// ============================================================================ +// CWidgetInstaller::FinishInstallL() +// +// @since 3.1 +// ============================================================================ +// +EXPORT_C void CWidgetInstaller::FinishInstallL( TInt aErr ) + { +#ifdef _DEBUG + _LIT(KText, "FinishInstallL, aErr = %d, iOverwriting=%d"); + + if ( iCanLog ) + { + iFileLogger.WriteFormat( KText, aErr, iOverwriting ); + } +#endif + if ( EFalse == iServerConnected ) + { + User::LeaveIfError( iRegistry.Connect() ); + iServerConnected = ETrue; + } + + if ( !aErr ) + { + if ( iOverwriting ) + { + TUid uid = TUid::Uid( *(iPropertyValues[EUid]) ); + iRegistry.DeRegisterWidgetL( uid ); + iAppManager->DeregisterWidgetL( uid ); + } + iRegistry.RegisterWidgetL( iPropertyValues ); + iAppManager->RegisterWidgetL( *(iPropertyValues[EMainHTML]), + *(iPropertyValues[EBundleDisplayName]), + *(iPropertyValues[EIconPath]), + *(iPropertyValues[EDriveName]), + TUid::Uid( *(iPropertyValues[EUid]) ) ); + + if ( iOverwriting ) + { + // delete backup + TInt err = iFileMgr->RmDir( iBackupDir ); + } + } + else + { + if ( iOverwriting ) + { + // delete what was being installed, and restore previous + iFileMgr->RmDir( *(iPropertyValues[EBasePath]) ); + RestoreL(); + } + } + + iOverwriting = EFalse; + } + + /** + * @since 5.0 + */ +EXPORT_C void CWidgetInstaller::RegisterWidgetL( const TDesC& aMainHTML, + const TDesC& aBundleDisplayName, + const TDesC& aIconPath, + const TDesC& aDriveName, + const TUid& aUid ) + { + iAppManager->RegisterWidgetL( aMainHTML, aBundleDisplayName, + aIconPath, aDriveName, aUid ); + } + +/** + * @since 5.0 + */ +EXPORT_C void CWidgetInstaller::DeregisterWidgetL( const TUid& aUid ) + { + iAppManager->DeregisterWidgetL( aUid ); + } + +// ============================================================================ +// CWidgetInstaller::RunError() +// It is called by WidgetActiveCallback when InstallL leaves. +// +// @since 3.2 +// ============================================================================ +// +EXPORT_C TInt CWidgetInstaller::RunError( TInt aError ) + { + TRAP_IGNORE( FinishInstallL( aError ) ); + + return KErrNone; // indicates error was handled + } + +// ============================================================================ +// CWidgetInstaller::SetDriveAndCheckSpaceL() +// +// @since 3.2 +// ============================================================================ +// +TBool CWidgetInstaller::SetDriveAndCheckSpaceL() + { + TDriveUnit phoneMemDriveUnit( EDriveC ); + TInt64 driveSpace( 0 ); + + TInt error = DriveInfo( (TInt)phoneMemDriveUnit, driveSpace ); + if ( *(iPropertyValues[EFileSize]) > driveSpace ) + { + User::Leave( KErrNoMemory ); + } + + UpdateWidgetBasePathL( phoneMemDriveUnit ); + *(iPropertyValues[EDriveName]) = phoneMemDriveUnit.Name(); + + return ETrue; + } + +// ============================================================================ +// CWidgetInstaller::UpdateWidgetBasePathL() +// +// @since 3.1 +// ============================================================================ +// +void CWidgetInstaller::UpdateWidgetBasePathL( TDriveUnit& aDrive ) + { + const TDesC& bundleId = *(iPropertyValues[EBundleIdentifier]); + HBufC* basePath = HBufC::NewL( + aDrive.Name().Length() + KWidgetAppDir().Length() + + bundleId.Length() + 1 ); + basePath->Des().Append( aDrive.Name() ); + basePath->Des().Append( KWidgetAppDir ); + basePath->Des().Append( *(iPropertyValues[EBundleIdentifier]) ); + basePath->Des().Append( KBackSlash ); + + *(iPropertyValues[EBasePath]) = *basePath; + delete basePath; + } + +// ============================================================================ +// CWidgetInstaller::BackupL() +// When overwriting an installed widget, backup so can restore on error. +// +// @since 3.1 +// ============================================================================ +// +void CWidgetInstaller::BackupL() + { +#ifdef _DEBUG + _LIT(KText1, "inside BackupL, iOriginalDir=%S, iBackupDir=%S"); + + if ( iCanLog ) + { + iFileLogger.WriteFormat( KText1, &iOriginalDir, &iBackupDir ); + } +#endif + // if backup leaves, there is nothing caller needs to do to clean up + + // move to backup (by renaming) the existing install dir for the widget + + // first create a "unique" backup dir on the original dir drive + // (same drive required since can't "rename" across drives) + TParse p; + p.Set( iOriginalDir, NULL, NULL ); + TFileName path; + path.Copy( p.Drive() ); + path.Append( KWidgetAppDir ); + // NOT A GOOD WAY TO CREATE A UNIQUE DIRECTORY First we create a + // unique file and then delete it and then create a directory with + // same name. + RFile file; + CleanupClosePushL( file ); + User::LeaveIfError( file.Temp( iRfs, path, iBackupDir, EFileWrite ) ); + CleanupStack::PopAndDestroy(); // file + // delete the temp file and... + iFileMgr->Delete( iBackupDir ); + // ...convert to dir name + iBackupDir.Append( KBackSlash ); + + // make the backup + User::LeaveIfError( iFileMgr->Rename( iOriginalDir, iBackupDir ) ); + // overwriting boolean is only true when backup is successful + iOverwriting = ETrue; + } + +// ============================================================================ +// CWidgetInstaller::RestoreL() +// +// @since 3.1 +// ============================================================================ +// +void CWidgetInstaller::RestoreL() + { + // move (by renaming) the backup copy to the install dir for the widget + + // to assure a clean destination, try deleting install dir first + (void)iFileMgr->RmDir( iOriginalDir ); + + User::LeaveIfError( iFileMgr->Rename( iBackupDir, iOriginalDir ) ); + + // restore complete + iOverwriting = EFalse; + } + +// ============================================================================ +// CWidgetInstaller::DriveInfo +// Indicates if the given drive is available and ready to use. +// (other items were commented in a header). +// +// @since 3.2 +// ============================================================================ +// +TInt CWidgetInstaller::DriveInfo( TInt aDrive, TInt64& aDiskSpace ) + { + TInt error = KErrNone; + TVolumeInfo volumeInfo; + + error = iRfs.Volume( volumeInfo, aDrive ); + if( !error ) + { + aDiskSpace = volumeInfo.iFree; + } + + return error; + } + +// ============================================================================ +// CWidgetInstaller::SearchByExtL +// +// @since 3.2 +// ============================================================================ +// +TInt CWidgetInstaller::SearchByExtL( const TDesC& aDir, TUint aSortKey, const TDesC& aExt, TFileName& aFoundName ) + { + CDir* entryList = NULL; + TBool found = EFalse; + + // aDir = "\private\[WidgetBackupRestoreUid]\WidgetBURTemp\bundleID\" + TInt err = iRfs.GetDir( aDir, KEntryAttMatchMask, aSortKey, entryList ); + if ( err == KErrNone ) + { + CleanupStack::PushL(entryList); + + // check for directory entries + TInt extLen = aExt.Length(); + TInt cnt = entryList->Count(); + for (TInt i=0; iSetScanDataL( aDir, KEntryAttMatchMask, EDirsLast ); + + TInt64 dirSize = 0; + CDir* results = NULL; + scanner->NextL( results ); + while( results ) + { + CleanupStack::PushL( results ); + + // Prescan to get the dir file size. + TInt64 fileSize = 0; + const TInt count = results->Count(); + TInt i = 0; + for( i=0; iFullPath() ); + CleanupStack::PopAndDestroy( results ); + + scanner->NextL( results ); + } + + CleanupStack::PopAndDestroy(); // scanner + + return dirSize; + } + +// ============================================================================ +// CWidgetUIOperationsWatcher::ConvertIconL() +// Convert icon.png into mbm format for widget +// +// @since 5.0 +// ============================================================================ +// +void CWidgetInstaller::ConvertIconL( + TUid& aUid, + const TDesC& aIconPath ) + { + TFileName pngIcon; + pngIcon.Copy( aIconPath ); + + if ( pngIcon.Length() ) + { + pngIcon.Append( KIconFile ); + TFileName mbmIcon; + mbmIcon.Copy( aIconPath ); + mbmIcon.Append( aUid.Name() ); + mbmIcon.Append( KMBMExt() ); + + CIconConverter* iconConverter = CIconConverter::NewL( this, iRfs ); + CleanupStack::PushL(iconConverter); + + iconConverter->StartToDecodeL( pngIcon, mbmIcon ); + CActiveScheduler::Start(); // wait until the converter process finishes + CleanupStack::PopAndDestroy(); // iconConverter + } + } + +// ============================================================================ +// CWidgetInstaller::NotifyCompletionL() +// Icon conversion calls this when it is complete. +// +// @since 5.0 +// ============================================================================ +// +void CWidgetInstaller::NotifyCompletionL( TInt /*aErr*/ ) + { + CActiveScheduler::Stop(); + } + + +// ============================================================================ +// CWidgetInstaller::WidgetPropertiesFromInstalledWidgetL() +// Generates the widget property values from an already installed widget. +// +// @since 5.0 +// ============================================================================ +// +EXPORT_C RPointerArray* +CWidgetInstaller::WidgetPropertiesFromInstalledWidgetL( + RFs &aFs, + const TDesC& aWidgetPath, /* should end with backslash */ + const TDesC& aLproj, + TUid aUid ) + { + // output, ownership will be handed back to caller + RPointerArray* propertyValues = new (ELeave) + RPointerArray( + EWidgetPropertyIdCount ); + CleanupClosePushL( *propertyValues ); + + TInt i = 0; + // empty values + for ( ; i < EWidgetPropertyIdCount; ++i ) + { + CWidgetPropertyValue* value = CWidgetPropertyValue::NewL(); + User::LeaveIfError( propertyValues->Insert( value, i ) ); + } + *(*propertyValues)[EWidgetPropertyListVersion] = WIDGETPROPERTYLISTVERSION; + // UID + *(*propertyValues)[EUid] = aUid.iUid; + // size + TInt64 bundleRootSize = GetDirSizeL( aWidgetPath ); + if ( 0 == bundleRootSize ) + { + User::Leave( KErrNotSupported ); + } + *(*propertyValues)[EFileSize] = bundleRootSize; + // Info.plist + TFileName manifest ( aWidgetPath ); + manifest.Append( KInfoPList ); + RFile rFile; + User::LeaveIfError( rFile.Open( aFs, manifest, EFileRead ) ); + CleanupClosePushL( rFile ); + TInt size = 0; + rFile.Size( size ); + HBufC8* buffer = HBufC8::NewLC( size ); + TPtr8 bufferPtr( buffer->Des() ); + User::LeaveIfError( rFile.Read( bufferPtr ) ); + iWidgetConfigHandler->ParseValidateBundleMetadataL( + bufferPtr, *propertyValues, aFs ); + + CleanupStack::PopAndDestroy( ) ; // buffer + CleanupStack::Pop(); + rFile.Close(); + // update base path from metadata + *(*propertyValues)[EBasePath] = aWidgetPath; + // update drive name + *(*propertyValues)[EDriveName] = aWidgetPath.Left( 2 ); + // update main HTML + TFileName mainHtml( aWidgetPath ); + mainHtml.Append( *(*propertyValues)[EMainHTML] ); + *(*propertyValues)[EMainHTML] = mainHtml; + // update icon path, depends on Icon.png and mbm versions existing + TFileName iconFile( aWidgetPath ); + iconFile.Append( KIconFile ); + if ( BaflUtils::FileExists( aFs, iconFile ) ) + { + // scan the directory for mbm extension file with processed icon images + TFileName mbmFilename; + TBool mbmFound = SearchByExtL( aWidgetPath, + EDirsLast | EDescending, + KMBMExt, + mbmFilename ); + if ( mbmFound ) + { + // rename mbm file using supplied UID + // [A-Z]:\private\[WidgetUIUid]\[bundleID]\[zip-root]\[UID].mbm" + TFileName oldMbmFilename( aWidgetPath ); + oldMbmFilename.Append( mbmFilename ); + TFileName newMbmFilename( aWidgetPath ); + newMbmFilename.Append( aUid.Name() ); + newMbmFilename.Append( KMBMExt() ); + + TInt error = iRfs.Rename( oldMbmFilename, newMbmFilename ); + // it's ok that oldMbm and newMbm share the same uid + if( error != KErrNone && error != KErrAlreadyExists ) + { + User::Leave( error ); + } + *(*propertyValues)[EIconPath] = aWidgetPath; + } + } + + // localization of display name + TFileName infoLocFile( aWidgetPath ); + infoLocFile.Append( aLproj ); + infoLocFile.Append( KLprojExt ); + infoLocFile.Append( KBackSlash ); + infoLocFile.Append( KInfoPlistStrings ); + TInt error = rFile.Open( aFs, infoLocFile, EFileRead ); + CleanupClosePushL( rFile ); + if ( error == KErrNone ) + { + TInt size = 0; + rFile.Size( size ); + HBufC8* buffer = HBufC8::NewLC( size ); + TPtr8 bufferPtr( buffer->Des() ); + error = rFile.Read( bufferPtr ); + User::LeaveIfError( error ); + // parse the l10n file and localize the bundle display name + iWidgetConfigHandler->ParseInfoLocL( + bufferPtr, aFs, *(*propertyValues)[EBundleDisplayName] ); + CleanupStack::PopAndDestroy( ); // buffer + } + + + CleanupStack::Pop( 2 ); // rfile, propertyValues + rFile.Close(); + return propertyValues; + } + +EXPORT_C TInt CWidgetInstaller::RenameIconFile( + RFs &aFs, + RPointerArray* aEntry ) + { + // update icon path, depends on Icon.png and mbm versions existing + const TDesC& mainHtml = *(*aEntry)[EMainHTML]; + TInt mainHtmlPathEnd = mainHtml.LocateReverse( TChar( '\\' ) ); + if ( KErrNotFound == mainHtmlPathEnd ) + { + return KErrNotFound; + } + TFileName mainPath( mainHtml.Left( mainHtmlPathEnd + 1 ) ); + TFileName iconFile( mainPath ); + iconFile.Append( KIconFile ); + if ( BaflUtils::FileExists( aFs, iconFile ) ) + { + // scan the directory for mbm extension file with processed icon images + TFileName mbmFilename; + TBool mbmFound = SearchByExtL( mainPath, + EDirsLast | EDescending, + KMBMExt, + mbmFilename ); + if ( mbmFound ) + { + // rename mbm file using supplied UID + // [A-Z]:\private\[WidgetUIUid]\[bundleID]\[zip-root]\[UID].mbm" + TFileName oldMbmFilename( mainPath ); + oldMbmFilename.Append( mbmFilename ); + TFileName newMbmFilename( mainPath ); + TInt uid = *(*aEntry)[EUid]; + newMbmFilename.Append( TUid::Uid(uid).Name() ); + newMbmFilename.Append( KMBMExt() ); + + // it's ok that oldMbm and newMbm share the same uid + TInt error = iRfs.Rename( oldMbmFilename, newMbmFilename ); + if( error != KErrNone && error != KErrAlreadyExists ) + { + return error; + } + *(*aEntry)[EIconPath] = mainPath; + } + } + return KErrNone; + } + +// End of File