appinstaller/AppMngr2/src/appmngr2model.cpp
changeset 0 ba25891c3a9e
child 9 51c0f5edf5ef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/appinstaller/AppMngr2/src/appmngr2model.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,839 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:   Model implementation
+*
+*/
+
+
+#include "appmngr2model.h"              // CAppMngr2Model
+#include "appmngr2modelobserver.h"      // CAppMngr2ModelObserver
+#include "appmngr2infomaker.h"          // CAppMngr2InfoMaker
+#include "appmngr2appinfomaker.h"       // CAppMngr2AppInfoMaker
+#include "appmngr2packageinfomaker.h"   // CAppMngr2PackageInfoMaker
+#include "appmngr2appinfoarray.h"       // CAppMngr2AppInfoArray
+#include "appmngr2packageinfoarray.h"   // CAppMngr2PackageInfoArray
+#include "appmngr2scanner.h"            // CAppMngr2Scanner
+#include "appmngr2pluginholder.h"       // CAppMngr2PluginHolder
+#include <appmngr2runtime.h>            // CAppMngr2Runtime
+#include <appmngr2infobase.h>           // CAppMngrInfoBase
+#include <appmngr2appinfo.h>            // CAppMngr2AppInfo
+#include <appmngr2packageinfo.h>        // CAppMngr2PackageInfo
+#include <appmngr2recognizedfile.h>     // CAppMngr2RecognizedFile
+#include <appmngr2cleanuputils.h>       // CleanupResetAndDestroyPushL
+#include <appmngr2driveutils.h>         // TAppMngr2DriveUtils
+#include <appmngr2common.hrh>           // generic command ids
+#include <ecom/implementationinformation.h>  // CImplementationInformation
+#include <ecom/ecom.h>                  // REComSession
+#include <AknIconArray.h>               // CAknIconArray
+#include <gulicon.h>                    // CGulIcon
+#include <driveinfo.h>                  // DriveInfo
+#include <pathinfo.h>                   // Pathinfo
+#include <centralrepository.h>          // CRepository
+#include <SWInstallerInternalCRKeys.h>  // KCRUidSWInstallerLV
+#include <AknsUtils.h>                  // AknsUtils
+#include <appmngr2.mbg>                 // icon IDs
+
+_LIT( KAppMngr2BitmapFile, "appmngr2.mif" );
+_LIT( KDriveSpec, "%c:" );
+
+
+// ======== LOCAL FUNCTIONS =========
+
+// ---------------------------------------------------------------------------
+// FindDataType()
+// ---------------------------------------------------------------------------
+//
+TBool FindDataType( const TDataType& aDataType, CDataTypeArray& aArray )
+    {
+    TInt count = aArray.Count();
+    for( TInt index = 0; index < count; index++ )
+        {
+        if( aArray[ index ] == aDataType )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::NewL()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2Model* CAppMngr2Model::NewL( RFs& aFsSession,
+        MAppMngr2ModelObserver& aObserver )
+    {
+    CAppMngr2Model* self = new (ELeave) CAppMngr2Model( aFsSession, aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::~CAppMngr2Model()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2Model::~CAppMngr2Model()
+    {
+    FLOG( "CAppMngr2Model::~CAppMngr2Model" );
+    iClosing = ETrue;   // to disable notifications
+
+    Cancel();
+    delete iApaAppListNotifier;
+    iInfoMakers.ResetAndDestroy();
+    delete iScanner;
+    delete iInstalledApps;
+    delete iInstallationFiles;
+    iPlugins.ResetAndDestroy();     // unloads plugin DLLs
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::AppInfoCount()
+// ---------------------------------------------------------------------------
+//
+TInt CAppMngr2Model::AppInfoCount() const
+    {
+    return iInstalledApps->Count();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::AppInfo()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2AppInfo& CAppMngr2Model::AppInfo( TInt aIndex ) const
+    {
+    return *( reinterpret_cast< CAppMngr2AppInfo* >( iInstalledApps->At( aIndex ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::PackageInfoCount()
+// ---------------------------------------------------------------------------
+//
+TInt CAppMngr2Model::PackageInfoCount() const
+    {
+    return iInstallationFiles->Count();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::PackageInfo()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2PackageInfo& CAppMngr2Model::PackageInfo( TInt aIndex ) const 
+    {
+    return *( reinterpret_cast< CAppMngr2PackageInfo* >( iInstallationFiles->At( aIndex ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::LoadIconsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::LoadIconsL( CAknIconArray& aIconArray )
+    {
+    LoadDefaultIconsL( aIconArray );
+    
+    TInt pluginCount = iPlugins.Count();
+    for( TInt index = 0; index < pluginCount; index++ )
+        {
+        iPlugins[ index ]->LoadIconsL( aIconArray );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::GetIconIndexesL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::GetIconIndexesL( TUid aUid, TInt& aIconIndexBase, TInt& aIconIndexMax ) const
+    {
+    TInt pluginCount = iPlugins.Count();
+    for( TInt index = 0; index < pluginCount; index++ )
+        {
+        if( iPlugins[ index ]->Runtime().RuntimeUid() == aUid )
+            {
+            aIconIndexBase = iPlugins[ index ]->IconIndexBase();
+            aIconIndexMax = iPlugins[ index ]->IconIndexMax();
+            return;
+            }
+        }
+    User::Leave( KErrNotFound );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::HandleCommandL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::HandleCommandL( CAppMngr2InfoBase& aInfo, TInt aCommand )
+    {
+    FLOG( "CAppMngr2Model::HandleCommandL( %d ), IsActive() = %d", aCommand, IsActive() );
+    
+    if( !IsActive() )
+        {
+        // About to start plugin specific command. Note that when the command completes
+        // we need to call CAppMngr2InfoBase::CommandComplete() function. For this (and
+        // to indicate that there is a plugin specific command on-going) we take the
+        // address of CAppMngr2InfoBase item into iActiveItem. Because plugin specific
+        // command (like delete or uninstall) may trigger new scanning, it is necessary
+        // to disable iInstalledApps and iInstallationFiles array refreshing temporarily.
+        // When refreshing is disabled, the item which address is stored in iActiveItem
+        // is maintained in arrays and we can call iActiveItem->CommandComplete() when
+        // the command is complete. If arrays could be refreshed during plugin specific
+        // command, then calling iActiveItem->CommandComplete() would panic.
+        if( iObs.InstalledAppsDisplayed() )
+            {
+            iInstalledApps->DisableRefreshNotificationsL();
+            }
+        if( iObs.InstallationFilesDisplayed() )
+            {
+            iInstallationFiles->DisableRefreshNotificationsL();
+            }
+
+        iActiveItem = &aInfo;
+        iActiveCommand = aCommand;
+        FLOG( "CAppMngr2Model::HandleCommandL, iActiveItem = 0x%08x '%S'",
+                iActiveItem, &( iActiveItem->Name() ) ); 
+        TRAPD( err, iActiveItem->HandleCommandL( aCommand, iStatus ) );
+        FLOG( "CAppMngr2Model::HandleCommandL, command started, err = %d", err );
+        SetActive();
+        if( err )
+            {
+            TRequestStatus* statusPtr = &iStatus;
+            User::RequestComplete( statusPtr, err );
+            }
+        }
+    // Ignore the command silently if already active. This may happen when user
+    // cancels previous installation command. Because cancelling installation can
+    // take long time, user may be able to issue new commands while model is still
+    // active (i.e. previous installation command is being cancalled).
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::StartFetchingInstallationFilesL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::StartFetchingInstallationFilesL()
+    {
+    FLOG( "CAppMngr2Model::StartFetchingInstallationFilesL" );
+    FLOG_PERF_START( FetchInstallationFiles )
+    
+    // Installation files cache must be enabled until scanner has completed.
+    // This ensures that scanner has time to call GetInstallationFilesL() for
+    // each plugin and for each directory before the first call completes.
+    // If the first call completes before scanner has made all these requets,
+    // cache will be turned off and partial results are displayed.
+    iInstallationFiles->IncrementCacheUseStartingNewRoundL();
+
+    iScanner->StartScanningL();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::StartFetchingInstalledAppsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::StartFetchingInstalledAppsL()
+    {
+    FLOG( "CAppMngr2Model::StartFetchingInstalledAppsL" );
+    FLOG_PERF_START( FetchInstalledApps )
+
+    // Additional cache increment to ensure that iInstalledApps cache is
+    // used until GetInstalledAppsL() function is called for each plugin.
+    // Without this, the fastest plugin might get it's list complete before
+    // other IncrementCacheUseL() calls and iInstalledApps would display
+    // partial list.
+    iInstalledApps->IncrementCacheUseStartingNewRoundL();
+    
+    TInt pluginCount = iPlugins.Count();
+    for( TInt pluginIndex = 0; pluginIndex < pluginCount; pluginIndex++ )
+        {
+        CAppMngr2AppInfoMaker* appInfoMaker = CAppMngr2AppInfoMaker::NewLC(
+                iPlugins[ pluginIndex ]->Runtime(), *this, iFs );
+        
+        TRAPD( err, appInfoMaker->StartGettingInstalledAppsL() );
+        FLOG( "CAppMngr2Model::StartFetchingInstalledAppsL, plugin 0x%08x, err = %d",
+                iPlugins[ pluginIndex ]->Runtime().RuntimeUid().iUid, err );
+        if( err == KErrNone )
+            {
+            iInfoMakers.AppendL( appInfoMaker );
+            CleanupStack::Pop( appInfoMaker );
+            iInstalledApps->IncrementCacheUseL();
+            }
+        else
+            {
+            CleanupStack::PopAndDestroy( appInfoMaker );
+            }
+        }
+
+    // All GetInstalledAppsL() requests have been issued
+    iInstalledApps->DecrementCacheUse();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::DoCancel()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::DoCancel()
+    {
+    FLOG( "CAppMngr2Model::DoCancel, iActiveItem = 0x%08x", iActiveItem );
+    
+    if( iActiveItem )
+        {
+        iActiveItem->CancelCommand();
+        iActiveItem = NULL;
+        if( !iClosing )
+            {
+            TRAP_IGNORE( iInstalledApps->EnableRefreshNotificationsL() );
+            TRAP_IGNORE( iInstallationFiles->EnableRefreshNotificationsL() );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::RunL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::RunL()
+    {
+    FLOG( "CAppMngr2Model::RunL, iActiveItem = 0x%08x, iStatus = %d",
+            iActiveItem, iStatus.Int() );
+
+    if( iActiveItem )
+        {
+        TInt completionCode = iStatus.Int();
+        TRAPD( err, iActiveItem->HandleCommandResultL( completionCode ) );
+        FLOG( "CAppMngr2Model::RunL, HandleCommandResultL err = %d", err );
+        CAppMngr2InfoBase* itemToDelete = iActiveItem;
+        iActiveItem = NULL;
+
+        // Enable refresh notifications. No need to check which view is active
+        // because notifications can be enabled even if they were not disabled.
+        iInstalledApps->EnableRefreshNotificationsL();
+        iInstallationFiles->EnableRefreshNotificationsL();
+
+        // Leave on error. This displays error note (if error notes are enabled).
+        User::LeaveIfError( err );
+        
+        // If the command is EAppMngr2CmdUninstall or EAppMngr2CmdRemove, and it
+        // completed without errors, then we remove the current item immediatelty
+        // from the displayed list. Otherwise it may take quite long time until
+        // the item is removed from the UI, and in worst case it may not be removed
+        // at all.
+        // For example when an installation file is deleted, scanner notices change
+        // in directories and re-scans everything. UI is updated when the scanning
+        // completes. Delay between delete command and UI update (deleted item is
+        // removed from UI) depends on how quickly scanning completes.
+        if( completionCode == KErrNone )
+            {
+            if( iActiveCommand == EAppMngr2CmdUninstall && iObs.InstalledAppsDisplayed() )
+                {
+                iInstalledApps->ImmediateDelete( itemToDelete );
+                }
+            if( iActiveCommand == EAppMngr2CmdRemove && iObs.InstallationFilesDisplayed() )
+                {
+                iInstallationFiles->ImmediateDelete( itemToDelete );
+                }
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::RefreshInstalledApps()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::RefreshInstalledApps()
+    {
+    FLOG( "CAppMngr2Model::RefreshInstalledApps" );
+    
+    TRAP_IGNORE( StartFetchingInstalledAppsL() );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::RefreshInstallationFiles()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::RefreshInstallationFiles()
+    {
+    FLOG( "CAppMngr2Model::RefreshInstallationFiles" );
+
+    TRAP_IGNORE( StartFetchingInstallationFilesL() );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ScanningResultL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ScanningResultL( RPointerArray<CAppMngr2RecognizedFile>& aResult )
+    {
+    FLOG( "CAppMngr2Model::ScanningResultL, begin: aResult.Count() = %d", aResult.Count() );
+    
+    // Split recognition result array into smaller (plugin specific) arrays. Plugin
+    // specific arrays are maintained by CAppMngr2PackageInfoMaker objects, so one
+    // CAppMngr2PackageInfoMaker object is needed for each plugin that has recognized
+    // files.
+    TInt pluginCount = iPlugins.Count();
+    for( TInt pluginIndex = 0; pluginIndex < pluginCount; pluginIndex++ )
+        {
+        CAppMngr2PackageInfoMaker* packageInfoMaker = CAppMngr2PackageInfoMaker::NewLC(
+                iPlugins[ pluginIndex ]->Runtime(), *this, iFs );
+
+        TInt fileCount = 0;
+        TInt resultCount = aResult.Count();
+        for( TInt resultIndex = resultCount - 1; resultIndex >= 0; resultIndex-- )
+            {
+            CAppMngr2RecognizedFile* recFile = aResult[ resultIndex ];
+            if( FindDataType( recFile->DataType(), iPlugins[ pluginIndex ]->DataTypes() ) )
+                {
+                packageInfoMaker->AddFileL( recFile );  // takes ownership
+                aResult.Remove( resultIndex );
+                fileCount++;
+                }
+            }
+
+        FLOG( "CAppMngr2Model::ScanningResultL, plugin 0x%08x: fileCount = %d",
+                iPlugins[ pluginIndex ]->Runtime().RuntimeUid().iUid, fileCount );
+        if( fileCount > 0 )
+            {
+            packageInfoMaker->StartGettingInstallationFilesL();
+            iInfoMakers.AppendL( packageInfoMaker );
+            CleanupStack::Pop( packageInfoMaker );
+            iInstallationFiles->IncrementCacheUseL();
+            }
+        else
+            {
+            CleanupStack::PopAndDestroy( packageInfoMaker );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ScanningComplete()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ScanningComplete()
+    {
+    FLOG( "CAppMngr2Model::ScanningComplete" );
+    
+    iInstallationFiles->DecrementCacheUse();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::DirectoryChangedL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::DirectoryChangedL( const TDesC& /*aChangedDir*/ )
+    {
+    FLOG( "CAppMngr2Model::DirectoryChangedL" );
+    
+    // This might be improved by scanning the changed directory only. Model
+    // could record which items are got from which directory, so that it could
+    // remove those items that were created from the changed directory and
+    // re-scan only the changed directory. Scanner should also support
+    // scanning one directory only. Now, we just scan all again.
+    StartFetchingInstallationFilesL();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::HandleAppListEvent()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::HandleAppListEvent( TInt /*aEvent*/ )
+    {
+    FLOG( "CAppMngr2Model::HandleAppListEvent" );
+    
+    TRAP_IGNORE( StartFetchingInstalledAppsL() );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::NewAppsCreatedL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::NewAppsCreatedL( const CAppMngr2InfoMaker& aMaker,
+        RPointerArray<CAppMngr2AppInfo>& aAppInfos )
+    {
+    FLOG( "CAppMngr2Model::NewAppsCreatedL, plugin 0x%08x: packageCount = %d",
+            aMaker.RuntimeUid().iUid, aAppInfos.Count() );
+    
+    iInstalledApps->AddItemsInOrderL( aAppInfos );
+    iInstalledApps->DecrementCacheUse();
+    CloseInfoMaker( aMaker );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ErrorInCreatingAppsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ErrorInCreatingAppsL( const CAppMngr2InfoMaker& aMaker,
+#ifdef FLOG_DEBUG_TRACES
+        TInt aError )
+#else
+        TInt /*aError*/ )
+#endif
+    {
+    FLOG( "CAppMngr2Model::ErrorInCreatingAppsL, plugin 0x%08x: error = %d",
+            aMaker.RuntimeUid().iUid, aError );
+    
+    iInstalledApps->DecrementCacheUse();
+    CloseInfoMaker( aMaker );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::NewPackagesCreatedL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::NewPackagesCreatedL( const CAppMngr2InfoMaker& aMaker,
+            RPointerArray<CAppMngr2PackageInfo>& aPackageInfos )
+    {
+    FLOG( "CAppMngr2Model::NewPackagesCreatedL, plugin 0x%08x: packageCount = %d",
+            aMaker.RuntimeUid().iUid, aPackageInfos.Count() );
+    
+    iInstallationFiles->AddItemsInOrderL( aPackageInfos );
+    iInstallationFiles->DecrementCacheUse();
+    CloseInfoMaker( aMaker );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ErrorInCreatingPackagesL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ErrorInCreatingPackagesL( const CAppMngr2InfoMaker& aMaker,
+#ifdef FLOG_DEBUG_TRACES
+        TInt aError )
+#else
+        TInt /*aError*/ )
+#endif
+    {
+    FLOG( "CAppMngr2Model::ErrorInCreatingPackagesL, plugin 0x%08x: error = %d",
+            aMaker.RuntimeUid().iUid, aError );
+    
+    iInstallationFiles->DecrementCacheUse();
+    CloseInfoMaker( aMaker );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ArrayContentChanged()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ArrayContentChanged( CAppMngr2InfoArray* aArray,
+        TInt aMoreRefreshesExpected )
+    {
+    if( aArray == iInstalledApps )
+        {
+        FLOG_PERF_STOP( FetchInstalledApps )
+        FLOG_PERF_PRINT( FetchInstalledApps )
+        iObs.InstalledAppsChanged( aMoreRefreshesExpected );
+        }
+    if( aArray == iInstallationFiles )
+        {
+        FLOG_PERF_STOP( FetchInstallationFiles )
+        FLOG_PERF_PRINT( FetchInstallationFiles )
+        iObs.InstallationFilesChanged( aMoreRefreshesExpected );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::CAppMngr2Model()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2Model::CAppMngr2Model( RFs& aFsSession, MAppMngr2ModelObserver& aObserver )
+        : CActive( CActive::EPriorityStandard ), iFs( aFsSession ), iObs( aObserver )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::ConstructL()
+    {
+    FLOG( "CAppMngr2Model::ConstructL" );
+    iClosing = EFalse;
+
+    iInstalledApps = CAppMngr2AppInfoArray::NewL( *this );
+    iInstallationFiles = CAppMngr2PackageInfoArray::NewL( *this );
+    
+    FLOG_PERF_STATIC_BEGIN( LoadPluginsL )
+    LoadPluginsL();
+    FLOG_PERF_STATIC_END( LoadPluginsL )
+    FLOG_PERF_STATIC_BEGIN( CreateScannerL )
+    CreateScannerL();
+    FLOG_PERF_STATIC_END( CreateScannerL )
+    FLOG_PERF_STATIC_BEGIN( FetchDataTypesL )
+    FetchDataTypesL();
+    FLOG_PERF_STATIC_END( FetchDataTypesL )
+
+    // start monitoring changes in applications list
+    iApaAppListNotifier = CApaAppListNotifier::NewL( this, CActive::EPriorityStandard );
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::LoadDefaultIconsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::LoadDefaultIconsL( CAknIconArray& aIconArray )
+    {
+    FLOG( "CAppMngr2Model::LoadDefaultIconsL" );
+    
+    MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
+    HBufC* bitmapFile = TAppMngr2DriveUtils::FullBitmapFileNameLC( KAppMngr2BitmapFile, iFs );
+    CFbsBitmap* bitmap = NULL;
+    CFbsBitmap* mask = NULL;
+    CGulIcon* icon = NULL;
+    
+    // Note that icons can be graphically-skinned (icon graphic defined in theme)
+    // or color-skinned (icon colors change depending on background color defined
+    // in theme). Normal icons are graphically-skinned and indicator icons are
+    // color-skinned. AknsUtils::CreateGulIconL() creates graphically-skinned icons,
+    // and AknsUtils::CreateColorIconL() creates color-skinned icons. Hence both
+    // of these functions are used below.
+
+    // Icon 0: EAppMngr2IconIndex_QgnIndiAmInstMmcAdd
+    // Indicator icon for items stored/installed in memory card
+    AknsUtils::CreateColorIconLC( skinInstance, 
+            KAknsIIDQgnIndiMmcAdd, KAknsIIDQsnIconColors, EAknsCIQsnIconColorsCG13,
+            bitmap, mask, *bitmapFile, 
+            EMbmAppmngr2Qgn_indi_mmc_add,
+            EMbmAppmngr2Qgn_indi_mmc_add_mask,
+            KRgbBlack );
+    icon = CGulIcon::NewL( bitmap, mask );
+    icon->SetBitmapsOwnedExternally( EFalse );
+    CleanupStack::Pop( 2 );   // bitmap and mask, order is varying
+    CleanupStack::PushL( icon );
+    aIconArray.AppendL( icon );
+    CleanupStack::Pop( icon );
+
+    // Icon 1: EAppMngr2IconIndex_QgnIndiFmgrMsAdd
+    // Indicator icon for items stored/installed in mass memory
+    AknsUtils::CreateColorIconLC( skinInstance, 
+            KAknsIIDQgnIndiFmgrMsAdd, KAknsIIDQsnIconColors, EAknsCIQsnIconColorsCG13,
+            bitmap, mask, *bitmapFile, 
+            EMbmAppmngr2Qgn_indi_fmgr_ms_add,
+            EMbmAppmngr2Qgn_indi_fmgr_ms_add_mask,
+            KRgbBlack );
+    icon = CGulIcon::NewL( bitmap, mask );
+    icon->SetBitmapsOwnedExternally( EFalse );
+    CleanupStack::Pop( 2 );   // bitmap and mask, order may vary
+    CleanupStack::PushL( icon );
+    aIconArray.AppendL( icon );
+    CleanupStack::Pop( icon );
+
+    // Icon 2: EAppMngr2IconIndex_QgnPropUnknown
+    // List icon for items that are not known
+    icon = AknsUtils::CreateGulIconL( skinInstance,
+            KAknsIIDQgnPropUnknown, *bitmapFile,
+            EMbmAppmngr2Qgn_prop_unknown, 
+            EMbmAppmngr2Qgn_prop_unknown_mask );
+    CleanupStack::PushL( icon );
+    aIconArray.AppendL( icon );
+    CleanupStack::Pop( icon );
+
+    CleanupStack::PopAndDestroy( bitmapFile );
+    
+    // Additionally some unknown indicator icon could be defined.
+    // Now, if some plugin gives incorrect index fox indicator icon,
+    // then no indicator icon is displayed.
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::LoadPluginsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::LoadPluginsL()
+    {
+    FLOG( "CAppMngr2Model::LoadPluginsL" );
+    
+    RImplInfoPtrArray implInfoArray;
+    CleanupResetAndDestroyPushL( implInfoArray  );
+    REComSession::ListImplementationsL( KAppMngr2PluginInterface, implInfoArray );
+
+    CAppMngr2PluginHolder* pluginHolder = NULL;
+    CImplementationInformation* implInfo;
+    TInt count = implInfoArray.Count();
+    for( TInt index = 0; index < count; index++ )
+        {
+        implInfo = implInfoArray[ index ];
+        FLOG( "CAppMngr2Model::LoadPluginsL, loading %S", &( implInfo->DisplayName() ) );
+        FLOG_PERF_STATIC_BEGIN( DoLoadPluginL );
+        TRAPD( err, pluginHolder = DoLoadPluginL( implInfo->ImplementationUid() ) );
+        FLOG_PERF_STATIC_END( DoLoadPluginL );
+        FLOG( "CAppMngr2Model::DoLoadPluginL( 0x%08x ), err = %d",
+                implInfo->ImplementationUid().iUid, err );
+        if( err == KErrNone )
+            {
+            CleanupStack::PushL( pluginHolder );
+            iPlugins.AppendL( pluginHolder );
+            CleanupStack::Pop( pluginHolder );
+            }
+        }
+
+    CleanupStack::PopAndDestroy( &implInfoArray );
+    REComSession::FinalClose();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::DoLoadPluginL()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2PluginHolder* CAppMngr2Model::DoLoadPluginL( TUid aUid )
+    {
+    CAppMngr2Runtime* plugin = CAppMngr2Runtime::NewL( aUid, *this );
+    CleanupStack::PushL( plugin );
+    CAppMngr2PluginHolder* holder = new (ELeave) CAppMngr2PluginHolder( plugin );
+    CleanupStack::Pop( plugin );
+    return holder;
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::CreateScannerL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::CreateScannerL()
+    {
+    iScanner = CAppMngr2Scanner::NewL( *this );
+
+    TDriveList driveList;
+    TInt driveCount = 0;
+    TInt err = DriveInfo::GetUserVisibleDrives( iFs, driveList, driveCount );
+    User::LeaveIfError( err );
+
+    // Default directories
+    TFileName path;
+    TInt driveListLength = driveList.Length();
+    for( TInt driveNumber = 0; driveNumber < driveListLength; driveNumber++ )
+        {
+        if( driveList[ driveNumber ] )
+            {
+            TUint driveStatus = 0;
+            err = DriveInfo::GetDriveStatus( iFs, driveNumber, driveStatus );
+            User::LeaveIfError( err );
+
+            if( !( driveStatus & DriveInfo::EDriveRemote ) )
+                {
+                err = PathInfo::GetFullPath( path, driveNumber, PathInfo::EInstallsPath );
+                User::LeaveIfError( err );
+                iScanner->AddDirectoryL( path );
+                }
+            }
+        }
+
+    // Additional plug-in specific directories
+    TInt pluginCount = iPlugins.Count();
+    for( TInt pluginIndex = 0; pluginIndex < pluginCount; pluginIndex++ )
+        {
+        RPointerArray<HBufC> dirsToScan;
+        CleanupResetAndDestroyPushL( dirsToScan );
+        TRAPD( err, iPlugins[ pluginIndex ]->Runtime().GetAdditionalDirsToScanL( iFs,
+                dirsToScan ) );
+        if( err == KErrNone )
+            {
+            TInt dirCount = dirsToScan.Count();
+            for( TInt dirIndex = 0; dirIndex < dirCount; dirIndex++ )
+                {
+                TPtrC dirName = *( dirsToScan[ dirIndex ] );
+                iScanner->AddDirectoryL( dirName );
+                }
+            }
+        CleanupStack::PopAndDestroy( &dirsToScan );
+        }
+    
+    // KSWInstallerPackageFolder directory if defined in CenRep
+    CRepository* cenrep = CRepository::NewLC( KCRUidSWInstallerLV );
+    err = cenrep->Get( KSWInstallerPackageFolder, path );
+    CleanupStack::PopAndDestroy( cenrep );
+    if( err == KErrNone )
+        {
+        TParsePtr parse( path );
+        if( parse.DrivePresent() )
+            {
+            iScanner->AddDirectoryL( path );
+            }
+        else if( parse.PathPresent() )
+            {
+            TDriveList driveList;
+            TInt driveCount = 0;
+            err = DriveInfo::GetUserVisibleDrives( iFs, driveList, driveCount );
+            if( err == KErrNone )
+                {
+                TInt driveListLength = driveList.Length();
+                for( TInt driveNumber = 0; driveNumber < driveListLength; driveNumber++ )
+                    {
+                    if( driveList[ driveNumber ] )
+                        {
+                        TUint driveStatus = 0;
+                        err = DriveInfo::GetDriveStatus( iFs, driveNumber, driveStatus );
+                        if( err == KErrNone && !( driveStatus & DriveInfo::EDriveRemote ) )
+                            {
+                            TChar driveLetter;
+                            if( RFs::DriveToChar( driveNumber, driveLetter ) == KErrNone )
+                                {
+                                TFileName fullPath;
+                                fullPath.Format( KDriveSpec, static_cast<TUint>( driveLetter ) );
+                                fullPath.Append( path ); 
+                                iScanner->AddDirectoryL( fullPath );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        else
+            {
+            // ignore empty values, and values that does not contain valid path
+            }
+        }
+    else
+        {
+        if( err != KErrNotFound )
+            {
+            User::Leave( err );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::FetchDataTypesL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::FetchDataTypesL()
+    {
+    FLOG( "CAppMngr2Model::FetchDataTypesL" );
+    
+    TInt pluginCount = iPlugins.Count();
+    for( TInt pluginIndex = 0; pluginIndex < pluginCount; pluginIndex++ )
+        {
+        FLOG( "CAppMngr2Model::FetchDataTypesL: pluginIndex = %d", pluginIndex );
+        TRAP_IGNORE( iPlugins[ pluginIndex ]->FetchDataTypesL() );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2Model::CloseInfoMaker()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2Model::CloseInfoMaker( const CAppMngr2InfoMaker& aMaker )
+    {
+    const CAppMngr2InfoMaker* makerToClose = &aMaker;
+    for( TInt index = iInfoMakers.Count() - 1; index >= 0; index-- )
+        {
+        CAppMngr2InfoMaker* maker = iInfoMakers[ index ]; 
+        if( maker == makerToClose )
+            {
+            iInfoMakers.Remove( index );
+            delete maker;
+            break;
+            }
+        }
+    }
+