--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/widgets/widgetinstaller/src/WidgetUIOperationsWatcher.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,1265 @@
+/*
+* 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 <f32file.h>
+#include <SWInstDefs.h>
+#include <zipfile.h>
+
+#include <SWInstTaskManager.h>
+#include <SWInstTask.h>
+#include <SWInstLogTaskParam.h>
+
+
+
+#include "WidgetUIOperationsWatcher.h"
+#include "WidgetUIConfigHandler.h" // info.plist parser
+#include "WidgetRegistrationManager.h" // interface to "shell"
+
+// CONSTANTS
+_LIT( KInfoPlist,"Info.plist" );
+_LIT( KIconFile, "Icon.png" );
+_LIT( KMBMExt, ".mbm");
+_LIT( KLprojExt, ".lproj" );
+_LIT( KInfoPlistStrings, "InfoPlist.strings" );
+_LIT( KWidgetAppDir, "\\private\\10282822\\" );
+_LIT( KCookieFile, "c:\\private\\101f8530\\cookies.dat" );
+
+
+const TUint KMaxDescLength = 0x0fffffffu;
+
+// Note about filenames: All file name matching is case insensitive
+// the EDriveName is stored as "c:" (withou a trailing backslash) all
+// filenames are kept as complete pathnames (drive + path + filename)
+// except when working with the widget bundle where the bundle
+// contains relative paths
+
+// TODO
+// filenames are kept as drive relative pathnames (path + filename but
+// not drive). The widget bundle must contain relative paths. The
+// drive letter is separated because support for multiple drives and
+// removable memory cards means that drive letters may change.
+
+
+using namespace SwiUI;
+
+// =========================== MEMBER FUNCTIONS ===============================
+
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::NewL()
+// two-phase constructor
+//
+// @since 3.1
+// @return pointer to CWidgetUIOperationsWatcher
+// ============================================================================
+//
+CWidgetUIOperationsWatcher* CWidgetUIOperationsWatcher::NewL()
+ {
+ CWidgetUIOperationsWatcher* self
+ = new (ELeave) CWidgetUIOperationsWatcher();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::CWidgetUIOperationsWatcher()
+// C++ constructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetUIOperationsWatcher::CWidgetUIOperationsWatcher()
+ : CActive( CActive::EPriorityStandard ),
+ iPropertyValues( EWidgetPropertyIdCount )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::ConstructL()
+// Symbian second phase constructor
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::ConstructL()
+ {
+ User::LeaveIfError( iRfs.Connect() );
+ User::LeaveIfError( iRfs.ShareProtected() );
+ iFileMgr = CFileMan::NewL( iRfs );
+
+ iAppManager = CWidgetRegistrationManager::NewL( iRfs );
+ iWidgetConfigHandler = CWidgetUIConfigHandler::NewL();
+
+ User::LeaveIfError( iRegistry.Connect() );
+ iServerConnected = ETrue;
+
+ TInt i = 0;
+ // empty values
+ for ( ; i < EWidgetPropertyIdCount; ++i )
+ {
+ CWidgetPropertyValue* value = CWidgetPropertyValue::NewL();
+ User::LeaveIfError( iPropertyValues.Insert( value, i ) );
+ }
+ *(iPropertyValues[EWidgetPropertyListVersion]) = WIDGETPROPERTYLISTVERSION;
+
+ iTaskManager = CTaskManager::NewL();
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::~CWidgetUIOperationsWatcher()
+// destructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetUIOperationsWatcher::~CWidgetUIOperationsWatcher()
+ {
+ CActive::Cancel();
+
+ TInt i = 0;
+ for ( ; i < EWidgetPropertyIdCount; ++i )
+ {
+ delete iPropertyValues[i];
+ }
+ iPropertyValues.Close();
+
+ delete iMembers;
+ delete iZipFile;
+
+ delete iFileMgr;
+ iRfs.Close();
+
+ delete iUIHandler;
+ delete iWidgetConfigHandler;
+ delete iAppManager;
+ delete iIconConverter;
+
+ if ( iServerConnected )
+ {
+ iRegistry.Disconnect();
+ }
+
+ delete iTaskManager;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::SilentInstallL()
+// Handle silent install request.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::SilentInstallL(
+ RFile& aFile,
+ const TDesC8& aMIME,
+ TRequestStatus& aRequestStatus )
+ {
+ iSilent = ETrue;
+ InstallL( aFile, aMIME, aRequestStatus );
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::InstallSubfunctionL()
+// Breaks out some install work inside trap macro because trap macro
+// intereferes with some debuggers.
+//
+// @since 5.0
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::InstallSubfunctionL(
+ RFile& aFile,
+ TBool& userCancel,
+ TRequestStatus& aRequestStatus )
+ {
+ iZipFile = CZipFile::NewL( iRfs, aFile );
+
+ // 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();
+
+ if ( PromptUserForInstallL( replaceExisting )
+ && PromptUserForUntrustedWidgetL( ) )
+ {
+ // reinitialize
+ delete iMembers;
+ iMembers = NULL;
+ iMembers = iZipFile->GetMembersL();
+
+ // now that install location is known, update MainHTML
+ const TDesC& base = *(iPropertyValues[EBasePath]);
+ const TDesC& main = *(iPropertyValues[EMainHTML]);
+ if ( KMaxFileName < (base.Length() + main.Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ TFileName tempFile;
+ tempFile.Copy( base );
+ tempFile.Append( main );
+ *(iPropertyValues[EMainHTML]) = tempFile;
+
+
+ // diplay explanation: 1. The progress display only comes up
+ // if the total size is over 1 kilobyte (this
+ // conditionalization is in UIHandler). 2. The displays stack
+ // on top of each other so if progress display comes up it
+ // will hide the finalize and then when progesss is removed,
+ // the finalize will be revealed. 3. Also, finalize failed to
+ // come up when triggered at the end of RunL() on a tiny
+ // widget file with no icon. Why, I'm not sure but probably
+ // had to do with this active object blocking display
+ // processing. So here is a good place to put up the displays
+ // (before RunL() is invoked) which lets other objects run.
+
+ iUIHandler->DisplayFinalizeDialogL(); // a dialog without a cancel option
+ iUIHandler->DisplayProgressDialogL(); // progress bar
+
+ if ( replaceExisting )
+ {
+ BackupL(); // nothing need be undone if backup leaves
+ // backup will gaurantee that install dir is empty
+
+ // now don't execute any leaving code before starting RunL
+ }
+ else
+ {
+ // new widget, allocate a UID for this widget
+ const TDesC& drive = *(iPropertyValues[EDriveName]);
+ *(iPropertyValues[EUid]) = iRegistry.GetAvailableUidL(drive[0]).iUid;
+
+ // check that install location is empty and remove what is
+ // there if it isn't
+ TUint attributes = 0;
+ TInt e = iRfs.Att( base, attributes );
+ if ( (KErrNotFound != e)
+ && (KErrPathNotFound != e) )
+ {
+ (void)iFileMgr->RmDir( base );
+ }
+ }
+ }
+ else
+ {
+ userCancel = ETrue;
+ iUIHandler->DisplayCancelL();
+ TRequestStatus* status = &aRequestStatus;
+ User::RequestComplete( status, KErrNone );
+ }
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::InstallL()
+// NORMAL INSTALL STEPS:
+// 1. open zip file
+// 2. get metadata file (e.g. Info.plist) and parse it
+// 3. prompt user to install (or replace identically named existing widget)
+// 4. prompt user for install location (built-in mem or mem card)
+// and do free space check
+// 5. if replacing existing widget then move currently installed files
+// to backup for possible restore on install error
+// 6. continue install in an active object runl to make install
+// cancellable also do icon processing in a separate active object
+// (the icon processing active object is a questionable design because
+// it doesn't follow the conventional CActive request/response pattern
+// and might as well be done here in the RunL)
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::InstallL(
+ RFile& aFile,
+ const TDesC8& /*aMIME*/,
+ TRequestStatus& aRequestStatus )
+ {
+ // Wrapper CWidgetInstallerUI::InstallL() guards against
+ // a second install request while currently installing.
+
+ iCancelled = EFalse;
+
+ // These three bools will be flase until doing something that
+ // needs to be cleaned up on error/cancel.
+ iUnzipping = EFalse;
+ iOverwriting = EFalse;
+ iProcessingIcon = EFalse;
+
+ iIconSearchFinished = EFalse;
+ iIconError = KErrNone;
+
+ // outside trap because without a UI we can't display an error message
+ iUIHandler =
+ CWidgetUIHandler::NewL( CWidgetUIHandler::EModeInstall, this );
+
+ TBool userCancel = EFalse;
+ TRAPD( error, InstallSubfunctionL( aFile, userCancel, aRequestStatus ) );
+ if ( KErrNone != error )
+ {
+ iUIHandler->DisplayErrorL( error );
+ User::Leave( error );
+ }
+ else if ( userCancel )
+ {
+ return; // can't do return inside trap
+ }
+
+ // start putting bundle files in install area, registy won't be
+ // changed until done unzipping and processing icon (if present)
+ iUnzipping = ETrue;
+
+ // set client request to pending state
+ iRequestStatus = &aRequestStatus;
+ *iRequestStatus = KRequestPending;
+
+ // start RunL
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ SetActive();
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::PreprocessWidgetBundleL()
+// Handles parsing and creating widget
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetUIOperationsWatcher::PreprocessWidgetBundleL()
+ {
+ TBool found = EFalse;
+
+ TFileName tempFile;
+ TFileName bundleRoot; // root dir in widget bundle (not install root)
+ TUint32 zipfileUncompressedSize = 0;
+
+ iMembers = iZipFile->GetMembersL();
+ if ( NULL == iMembers )
+ {
+ User::Leave( KErrNotSupported );
+ }
+ // compute total installed (uncompressed) size for use in progress
+ // meter (doesn't account for some derived things like scaled
+ // icons and registry data)
+ CZipFileMember* member = iMembers->NextL();
+ for ( ; member ; member = iMembers->NextL() )
+ {
+ zipfileUncompressedSize += member->UncompressedSize();
+ delete member;
+ }
+ if ( 0 == zipfileUncompressedSize )
+ {
+ User::Leave( KErrNotSupported );
+ }
+ *(iPropertyValues[EFileSize]) = zipfileUncompressedSize;
+
+ // find the top-level directory under which to get metadata
+ // TODO this isn't robust, check cases where there are multiple
+ // top-level dirs and no top-level dirs.
+ delete iMembers;
+ iMembers = NULL;
+ iMembers = iZipFile->GetMembersL();
+ member = iMembers->NextL();
+ TPtrC fName( *member->Name() );
+ TInt pos = fName.Locate( KPathDelimiter );
+ if ( (KErrNotFound == pos) || (KMaxFileName < pos) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+ bundleRoot.Copy( fName.Left( pos ) );
+ delete member;
+ delete iMembers;
+ iMembers = NULL;
+
+ // metadata file: "WeatherBug.wdgt\Info.plist"
+ if ( KMaxFileName
+ < (bundleRoot.Length() + 1 /* slash */ + KInfoPlist().Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ tempFile.Copy( bundleRoot );
+ tempFile.Append( KPathDelimiter );
+ tempFile.Append( KInfoPlist );
+ CZipFileMember* infoFileMember =
+ iZipFile->CaseInsensitiveMemberL( tempFile );
+ if ( NULL == infoFileMember )
+ {
+ // missing metadata file
+ User::Leave( KErrNotSupported );
+ }
+ CleanupStack::PushL( infoFileMember );
+
+ // we will use descriptors to handle the Info.plist contents so
+ // the file may not be larger than a descriptor can handle
+ if ( KMaxDescLength < infoFileMember->UncompressedSize() )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ // extract Info.plist from zip into a buffer
+ RZipFileMemberReaderStream* stream;
+ iZipFile->GetInputStreamL( infoFileMember, stream );
+ CleanupStack::PushL( stream );
+ HBufC8* buffer = HBufC8::NewLC( infoFileMember->UncompressedSize() );
+ TPtr8 bufferPtr( buffer->Des() );
+ User::LeaveIfError(
+ stream->Read( bufferPtr, infoFileMember->UncompressedSize() ) );
+
+ // METADATA PARSE
+ iWidgetConfigHandler->ParseValidateBundleMetadataL(
+ bufferPtr, iPropertyValues, iRfs );
+
+ CleanupStack::PopAndDestroy( 3 ); // infoFileMember, stream, buffer
+
+ // EXISTING WIDGET?
+ if( iRegistry.WidgetExistsL( *(iPropertyValues[EBundleIdentifier]) ) )
+ {
+ // replacement for currently installed widget
+ *(iPropertyValues[EUid]) = iRegistry.GetWidgetUidL(
+ *(iPropertyValues[EBundleIdentifier]));
+ found = ETrue;
+ if ( iRegistry.IsWidgetRunning(
+ TUid::Uid( *(iPropertyValues[EUid]) )) )
+ {
+ iUIHandler->CloseProgressDialogL();
+ User::Leave( KErrInUse );
+ }
+ // get original install dir from registry in case user
+ // decides to "overrite" to another memory location
+ iOriginalDir = *( iRegistry.GetWidgetPropertyValueL(
+ TUid::Uid( *(iPropertyValues[EUid]) ),
+ EBasePath ) );
+ }
+ // uid for a new widget will be gotten once install location (c: or
+ // e:) is selected
+
+ // see if main.html is in zip bundle
+ const TDesC& main = *(iPropertyValues[EMainHTML]);
+ if ( KMaxFileName
+ < (bundleRoot.Length() + 1 /* slash */ + main.Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ tempFile.Copy( bundleRoot );
+ tempFile.Append( KPathDelimiter );
+ tempFile.Append( main );
+ CZipFileMember* mainFileMember
+ = iZipFile->CaseInsensitiveMemberL( tempFile );
+ if ( !mainFileMember )
+ {
+ // missing main html file
+ User::Leave( KErrCorrupt );
+ }
+ delete mainFileMember;
+ mainFileMember = NULL;
+ // save MainHTML partial path to combine with base path when
+ // install location is selected
+ *(iPropertyValues[EMainHTML]) = tempFile;
+
+ // see if there is an Icon.png in root and get partial path
+ if ( KMaxFileName
+ < (bundleRoot.Length() + 1 /* slash */ + KIconFile().Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ tempFile.Copy( bundleRoot );
+ tempFile.Append( KPathDelimiter );
+ tempFile.Append( KIconFile );
+ CZipFileMember* iconFileMember
+ = iZipFile->CaseInsensitiveMemberL( tempFile );
+ if ( iconFileMember )
+ {
+ // save this partial path to identify Icon.png during unzip
+ *(iPropertyValues[EIconPath]) = tempFile;
+ }
+ else
+ {
+ iIconSearchFinished = ETrue;
+ }
+
+ // ex. infoLocFile pathname "WeatherBug.wdgt\en.lproj\InfoPlist.strings"
+ TBuf<32> lproj;
+ iRegistry.GetLprojName( lproj ); // e.g. "en", "fr", "zh_Hans" ...
+ if ( KMaxFileName
+ < (bundleRoot.Length() + 1 /* slash */ + lproj.Length()
+ + KLprojExt().Length() + 1 /* slash */
+ + KInfoPlistStrings().Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ TFileName infoLocFile( bundleRoot );
+ infoLocFile.Append( KPathDelimiter );
+ infoLocFile.Append( lproj );
+ infoLocFile.Append( KLprojExt );
+ infoLocFile.Append( KPathDelimiter );
+ infoLocFile.Append( KInfoPlistStrings );
+
+ CZipFileMember* infoLocFileMember =
+ iZipFile->CaseInsensitiveMemberL( infoLocFile );
+ if ( infoLocFileMember )
+ {
+ CleanupStack::PushL( infoLocFileMember );
+ RZipFileMemberReaderStream* stream;
+ iZipFile->GetInputStreamL( infoLocFileMember, stream );
+ CleanupStack::PushL( stream );
+
+ // we will use descriptors to handle the l10n contents so
+ // the file may not be larger than a descriptor can handle
+ if ( KMaxDescLength < infoLocFileMember->UncompressedSize() )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ HBufC8* buffer
+ = HBufC8::NewLC( infoLocFileMember->UncompressedSize() );
+ TPtr8 bufferPtr( buffer->Des() );
+ User::LeaveIfError(
+ stream->Read( bufferPtr, infoLocFileMember->UncompressedSize() ) );
+
+ // parse the l10n file and localize the bundle display name
+ iWidgetConfigHandler->ParseInfoLocL(
+ bufferPtr, iRfs, *(iPropertyValues[EBundleDisplayName]) );
+
+ CleanupStack::PopAndDestroy( 3 ); // buffer, stream, infoLocFileMember
+ }
+
+ return found;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::RunL()
+// RunL is called only for Intall/Overwrite. It's sole resposibilty is
+// unzipping the bundle files into the widget subdir.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::RunL()
+ {
+ if ( !iCancelled )
+ {
+ CZipFileMember* member = iMembers->NextL();
+ if ( member )
+ {
+ CleanupStack::PushL( member );
+
+ // build up the install pathname
+ TPtrC zipedFileName( *member->Name() );
+ TFileName zipedFileNameAndPath;
+ const TDesC& base = *(iPropertyValues[EBasePath]);
+ if ( KMaxFileName < (base.Length() + zipedFileName.Length()) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ zipedFileNameAndPath.Copy( base );
+ zipedFileNameAndPath.Append( zipedFileName );
+
+ // index is supposed to separate the path from the
+ // basename, unless it is just a directory
+ TInt index = zipedFileNameAndPath.LocateReverse( KPathDelimiter );
+ TPtrC path = zipedFileNameAndPath.Left( index + 1 /* slash */ );
+
+ // make the directory, it's dumb and will try to create
+ // directories that it has already created
+ TInt e = iRfs.MkDirAll( path );
+ if ( (KErrNone != e)
+ && (KErrAlreadyExists != e) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ // a member can be just a directory name but if it is a file
+ // then uncompress the contents
+ if ( zipedFileNameAndPath[zipedFileNameAndPath.Length()-1]
+ != KPathDelimiter ) // skip directory paths
+ {
+ // uncompress the compressed file into a buffer
+ RZipFileMemberReaderStream* stream;
+ iZipFile->GetInputStreamL( member, stream );
+ CleanupStack::PushL( stream );
+ TUint32 fileSize = member->UncompressedSize();
+ if ( KMaxDescLength < fileSize )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ HBufC8* buffer = HBufC8::NewLC( member->UncompressedSize() );
+ TPtr8 bufferPtr( buffer->Des() );
+ User::LeaveIfError(
+ stream->Read( bufferPtr, member->UncompressedSize() ) );
+
+ // write the buffer into a file
+ RFile file;
+ CleanupClosePushL( file );
+ User::LeaveIfError(
+ file.Create( iRfs, zipedFileNameAndPath, EFileWrite ) );
+ if ( fileSize > 0 )
+ {
+ User::LeaveIfError( file.Write( *buffer ) );
+ }
+ CleanupStack::PopAndDestroy( 3 ); // file, buffer, stream
+ }
+
+ // more progress!!!
+ if ( member->UncompressedSize() )
+ {
+ iUIHandler->UpdateProgressDialogL( member->UncompressedSize() );
+ }
+
+ // if this is the icon file, then start icon processing
+ if ( EFalse == iIconSearchFinished )
+ {
+ const TDesC& icon = *(iPropertyValues[EIconPath]);
+ if ( 0 == icon.CompareF( zipedFileName ) )
+ {
+ iIconSearchFinished = ETrue;
+ const TPtrC& path =
+ zipedFileNameAndPath.Left(index + 1 /* slash */ );
+ *(iPropertyValues[EIconPath]) = path;
+ TUid uid = TUid::Uid( *(iPropertyValues[EUid]) );
+ TRAPD( error, ConvertIconL( uid, path ) );
+ if ( KErrNone != error )
+ {
+ // forget the provided icon and proceed
+ iPropertyValues[EIconPath]->Reset();
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // member
+
+ // done with that file from the zip, go to next
+ TRequestStatus* stat = &iStatus;
+ User::RequestComplete( stat, KErrNone );
+ SetActive();
+ }
+ else // done with zip archive
+ {
+ iUIHandler->CloseProgressDialogL();
+ // and reveal finalize dialog underneath
+
+ // finished unzip
+ iUnzipping = EFalse;
+
+ if ( !iProcessingIcon )
+ {
+ FinishInstallL();
+ }
+ // if we are processing icons, then we wait for icon
+ // processing to complete
+
+ // don't call RequestComplete on installer status (the
+ // higher level caller's status) here because we are not
+ // done
+ }
+ }
+ else // user cancel (not DoCancel)
+ {
+ iUIHandler->CloseProgressDialogL();
+ iUIHandler->CloseFinalizeDialogL();
+ iUIHandler->DisplayCancelL();
+
+ // stop icon conversion (if there is a converter)
+ delete iIconConverter;
+ iIconConverter = NULL;
+ iProcessingIcon = EFalse;
+ iIconError = KErrNone;
+
+ iUnzipping = EFalse;
+
+ FinishInstallL();
+ }
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::NotifyCompletionL()
+// Icon conversion calls this when it is complete.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::NotifyCompletionL( TInt aErr )
+ {
+ iProcessingIcon = EFalse;
+ iIconError = aErr;
+
+ if ( KErrNone != iIconError )
+ {
+ iPropertyValues[EIconPath]->Reset();
+ }
+
+ // don't really need iCancelled in test as that combination
+ // shouldn't be possible
+ if ( !(iUnzipping || iCancelled) )
+ {
+ // NotifyCompletionL shouldn't ever leave since the caller
+ // is IconConverter and that is just a utility module.
+ TRAP_IGNORE( FinishInstallL() );
+ }
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::FinishInstallL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::FinishInstallL()
+ {
+ if ( !iCancelled )
+ {
+ if ( iOverwriting )
+ {
+ TUid uid = TUid::Uid( *(iPropertyValues[EUid]) );
+ iRegistry.DeRegisterWidgetL( uid );
+ iAppManager->DeregisterWidgetL( uid );
+ }
+
+ // TODO if registration steps fail does it leave inconsistent state???
+
+ iRegistry.RegisterWidgetL( iPropertyValues );
+
+ iAppManager->RegisterWidgetL( *(iPropertyValues[EMainHTML]),
+ *(iPropertyValues[EBundleDisplayName]),
+ *(iPropertyValues[EIconPath]),
+ *(iPropertyValues[EDriveName]),
+ TUid::Uid( *(iPropertyValues[EUid]) ) );
+
+ if ( iOverwriting )
+ {
+ // delete backup
+ (void)iFileMgr->RmDir( iBackupDir );
+ }
+
+ iUIHandler->CloseFinalizeDialogL();
+ iUIHandler->DisplayCompleteL();
+
+ HandleLogsL(*(iPropertyValues[EBundleDisplayName]), TUid::Uid( *(iPropertyValues[EUid]) ), *(iPropertyValues[ENokiaWidget]), SwiUI::ELogTaskActionInstall);
+ }
+ else // cancelled
+ {
+ // delete what was being installed, and restore previous
+ (void)iFileMgr->RmDir( *(iPropertyValues[EBasePath]) );
+
+ if ( iOverwriting )
+ {
+ RestoreL();
+ }
+ }
+
+ User::RequestComplete( iRequestStatus, KErrNone );
+ iRequestStatus = NULL;
+
+ iUnzipping = EFalse;
+ iOverwriting = EFalse;
+ iProcessingIcon = EFalse;
+ iIconError = KErrNone;
+ iCancelled = EFalse;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::UserCancelL()
+// If user selects cancel softkey on progress dialog only.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::UserCancelL( TBool /*aCancelImmediately*/ )
+ {
+ // It is only possible to get here while we have the progress
+ // dialog up during unzipping (iUnzipping is set). When unzipping
+ // finishes but icon processing is not finished, we display a
+ // finalize dialog without a cancel option.
+
+ iCancelled = ETrue;
+
+ // don't do anything other than set the flag as it will be tested
+ // while processing
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::DoCancel()
+// This should not be called directly. This function is called by
+// CActive when Cancel() is called on this object IF there is a
+// request outstanding. So indirectly it handles canceling the
+// install operation. Icon converter doesn't ever directly cause a
+// Cancel() even when it errors out because it is a service provider
+// to this object. If this method is called then RunL is not called
+// (they are mutually exclusive).
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::DoCancel()
+ {
+ // can't cancel uninstall because that is synchronous and runs in
+ // one step and this is only called by CActive if there is an
+ // outstanding request, that means we are in the prcess of
+ // unzipping the archive (but not in RunL presently), also note
+ // that this is not a user cancel (see separate function for that)
+
+ iCancelled = ETrue;
+
+ TRAP_IGNORE(
+ {
+ iUIHandler->CloseProgressDialogL();
+ iUIHandler->CloseFinalizeDialogL();
+ iUIHandler->DisplayCancelL();
+
+ // stop icon conversion (if there is a converter)
+ delete iIconConverter;
+ iIconConverter = NULL;
+ iProcessingIcon = EFalse;
+ iIconError = KErrNone;
+
+ iUnzipping = EFalse;
+
+ FinishInstallL();
+ }
+ );
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::RunError()
+// This should not be called directly. It is called by CActive when
+// RunL leaves. RunL is only for installing so this handles leaving
+// errors during installing widget.
+//
+// @since 3.1
+// ============================================================================
+//
+TInt CWidgetUIOperationsWatcher::RunError( TInt aError )
+ {
+ iCancelled = ETrue;
+ iUnzipping = EFalse;
+
+ TRAP_IGNORE(
+ {
+ iUIHandler->CloseProgressDialogL();
+ iUIHandler->CloseFinalizeDialogL();
+ iUIHandler->DisplayErrorL( aError );
+
+ // stop icon conversion (if there is a converter)
+ delete iIconConverter;
+ iIconConverter = NULL;
+ iProcessingIcon = EFalse;
+ iIconError = KErrNone;
+
+ FinishInstallL();
+ }
+ );
+
+ return KErrNone; // indicates error was handled
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::SilentUninstallL()
+// Handle silent uninstall request.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::SilentUninstallL(
+ const TUid& aUid,
+ TRequestStatus& aRequestStatus )
+ {
+ iSilent = ETrue;
+ UninstallL( aUid, aRequestStatus );
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::UninstallL()
+// Handle uninstall request.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::UninstallL(
+ const TUid& aUid,
+ TRequestStatus& aRequestStatus )
+ {
+ // initialize state
+ iCancelled = EFalse;
+ iUnzipping = EFalse;
+ iOverwriting = EFalse;
+ iProcessingIcon = EFalse;
+ iIconError = KErrNone;
+
+ // outside trap because without a UI we can't display an error message
+ iUIHandler =
+ CWidgetUIHandler::NewL( CWidgetUIHandler::EModeUninstall, this );
+
+ // save client status to use in finish uninstall
+ iRequestStatus = &aRequestStatus;
+
+ // TODO currently don't uninstall if running but in future should
+ // stop widget and then uninstall
+ if ( iRegistry.IsWidgetRunning( aUid ) )
+ {
+ FinishUninstallL( KErrInUse );
+ return;
+ }
+
+ TBuf<KWidgetRegistryVal> bundleName;
+ iRegistry.GetWidgetBundleName( aUid, bundleName );
+
+ if( bundleName.Length() <= 0 )
+ {
+ FinishUninstallL( KErrCorrupt );
+ return;
+ }
+
+ // prompt user to uninstall
+ if( iUIHandler->DisplayUninstallL( bundleName ) )
+ {
+ iUIHandler->DisplayUninstallInProgressL();
+ TBuf<KWidgetRegistryVal> widgetPath;
+ iRegistry.GetWidgetPath( aUid, widgetPath );
+ TBool aVendor = *(iRegistry.GetWidgetPropertyValueL(aUid, ENokiaWidget));
+
+
+ // TODO if any of next steps leave does state become inconsistent?
+
+ // remove the dir for the widget
+ // TODO why this validation?
+ if ( widgetPath.Length() > 0 )
+ {
+ iFileMgr->RmDir( widgetPath );
+ //Widget should delete any cookie it created
+ HBufC* fileName = HBufC::NewLC(KMaxFileName);
+ TPtr ptr(fileName->Des());
+ TBuf<8> buf1;
+ ptr = KCookieFile;
+ TInt pos = ptr.LocateReverse('.');
+ buf1.AppendNum(aUid.iUid,EHex);
+ ptr.Insert(pos,_L("_"));
+ ptr.Insert(pos+1,buf1);
+ iRfs.Delete(ptr);
+ CleanupStack::PopAndDestroy(fileName);
+ }
+
+ iRegistry.DeRegisterWidgetL( aUid );
+ iAppManager->DeregisterWidgetL( aUid );
+ TInt err = KErrNone;
+ TRAP(err, FinishUninstallL( KErrNone ));
+ if(err == KErrNone)
+ {
+ HandleLogsL(bundleName, aUid, aVendor, SwiUI::ELogTaskActionUninstall);
+ }
+ }
+ else
+ {
+ iUIHandler->DisplayCancelL();
+
+ // must return cancel because upper-levels will take uninstall
+ // actions (remove widget from applications list) if we return KErrNone
+ User::RequestComplete( iRequestStatus, KErrCancel );
+ return;
+ }
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::FinishUninstallL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::FinishUninstallL( TInt aErr )
+ {
+ iUIHandler->CloseUninstallInProgressDialogL();
+ if ( aErr )
+ {
+ iUIHandler->DisplayErrorL( aErr );
+ User::Leave( aErr );
+ }
+ iUIHandler->DisplayCompleteL();
+ User::RequestComplete( iRequestStatus, KErrNone );
+ iRequestStatus = NULL;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::IsShowingDialog()
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetUIOperationsWatcher::IsShowingDialog()
+ {
+ return ETrue;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::CancelEngine()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::CancelEngine()
+ {
+ // TODO ???
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::ForceCancel()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::ForceCancel()
+ {
+ // TODO ???
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::StartedCancellingL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::StartedCancellingL()
+ {
+ // TODO ???
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::SelectMemoryL()
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetUIOperationsWatcher::SelectMemoryL()
+ {
+ TDriveUnit selectedDrive;
+ TBool isSufficient = EFalse;
+
+ if ( !iUIHandler->SelectDriveL( iRfs,
+ selectedDrive, isSufficient,
+ *(iPropertyValues[EFileSize] )) )
+ {
+ UserCancelL();
+ return EFalse;
+ }
+ else if ( !isSufficient )
+ {
+ User::Leave( KErrNoMemory );
+ }
+
+ UpdateWidgetBasePathL( selectedDrive );
+ *(iPropertyValues[EDriveName]) = selectedDrive.Name();
+
+ return ETrue;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::UpdateWidgetBasePathL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::UpdateWidgetBasePathL( TDriveUnit& aDrive )
+ {
+ const TDesC& bundleId = *(iPropertyValues[EBundleIdentifier]);
+ HBufC* basePath = HBufC::NewL(
+ aDrive.Name().Length() + KWidgetAppDir().Length()
+ + bundleId.Length() + 1 /* slash */ );
+ basePath->Des().Append( aDrive.Name() );
+ basePath->Des().Append( KWidgetAppDir );
+ basePath->Des().Append( *(iPropertyValues[EBundleIdentifier]) );
+ basePath->Des().Append( KPathDelimiter );
+
+ *(iPropertyValues[EBasePath]) = *basePath;
+ delete basePath;
+ }
+
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::ConvertIconL()
+// Convert icon.png into mbm format for widget
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::ConvertIconL(
+ TUid& aUid,
+ const TDesC& aIconPath )
+ {
+ delete iIconConverter;
+ iIconConverter = NULL;
+
+ iIconConverter = CIconConverter::NewL( this, iRfs );
+
+ TFileName pngIcon;
+ pngIcon.Copy( aIconPath );
+
+ if ( pngIcon.Length() )
+ {
+ pngIcon.Append( KIconFile );
+ TFileName mbmIcon;
+ mbmIcon.Copy( aIconPath );
+ mbmIcon.Append( aUid.Name() );
+ mbmIcon.Append( KMBMExt() );
+
+ iIconConverter->StartToDecodeL( pngIcon, mbmIcon );
+ iProcessingIcon = ETrue;
+ }
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::PromptUserForInstallL()
+// Prompt to confirm install and where to install. SetActive() has not
+// been called yet.
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetUIOperationsWatcher::PromptUserForInstallL( TBool aOverwrite )
+ {
+ TBool userAnswer;
+
+ if ( aOverwrite )
+ {
+ userAnswer =
+ iUIHandler->DisplayOverwriteL( *(iPropertyValues[EBundleDisplayName]) );
+ }
+ else
+ {
+ userAnswer =
+ iUIHandler->DisplayInstallL( *(iPropertyValues[EBundleDisplayName]) );
+ }
+ if ( userAnswer )
+ {
+ userAnswer = SelectMemoryL();
+ }
+ return userAnswer;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::PromptUserForUntrustedWidgetL()
+// Prompt to confirm install of untrusted widget. SetActive() has not
+// been called yet.
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetUIOperationsWatcher::PromptUserForUntrustedWidgetL( )
+ {
+ TBool userAnswer(ETrue);
+
+ if ( !iSilent )
+ {
+ userAnswer = iUIHandler->DisplayUntrustedSecurityDialogL();
+ }
+
+ return userAnswer;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::BackupL()
+// When overwriting an installed widget, backup so can restore on error.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::BackupL()
+ {
+ // 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...
+ User::LeaveIfError( iFileMgr->Delete( iBackupDir ) );
+ // ...convert to dir name
+ iBackupDir.Append( KPathDelimiter );
+ // make the backup
+ User::LeaveIfError( iFileMgr->Rename( iOriginalDir, iBackupDir ) );
+ // original dir doesn't seem to be gone after rename so rmdir
+ // it...this is IMPORTANT because we want to be able to look at
+ // the list of install directories to get a list of installed
+ // widgets without checking if they are empty!
+ (void)iFileMgr->RmDir( iOriginalDir );
+ // overwriting boolean is only true when backup is successful
+ iOverwriting = ETrue;
+ }
+
+// ============================================================================
+// CWidgetUIOperationsWatcher::RestoreL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetUIOperationsWatcher::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 );
+
+ // TODO if this fails then do some cleanup, maybe unregister?
+ User::LeaveIfError( iFileMgr->Rename( iBackupDir, iOriginalDir ) );
+ // backup dir doesn't seem to be gone so rmdir it
+ (void)iFileMgr->RmDir( iBackupDir );
+
+ // restore complete
+ iOverwriting = EFalse;
+ }
+
+
+// ============================================================================
+//
+// CWidgetUIOperationsWatcher::HandleLogsL
+//
+// ============================================================================
+void CWidgetUIOperationsWatcher::HandleLogsL(const TDesC& aWidgetName, const TUid &aUid, TBool aVender, SwiUI::TLogTaskAction aAction)
+ {
+ CTask* task = CTask::NewL( KLogTaskImplUid, EFalse );
+ CleanupStack::PushL(task);
+
+ TLogTaskParam params;
+ params.iName.Copy(aWidgetName);
+ params.iUid = aUid;
+ params.iAction = aAction;
+ params.iVendor.Copy((aVender ? _L("Nokia") : _L("Non-Nokia")));
+
+ TTime time;
+ time.UniversalTime();
+ params.iTime = time;
+
+ TLogTaskParamPckg pckg( params );
+ task->SetParameterL( pckg, 0 );
+ iTaskManager->AddTaskL( task );
+ iTaskManager->CommitL();
+
+ CleanupStack::Pop(task);
+ }
+// End of File