diff -r 000000000000 -r 2e3d3ce01487 appfw/apparchitecture/aplist/aplapplist.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/appfw/apparchitecture/aplist/aplapplist.cpp Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,1767 @@ +// Copyright (c) 2006-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: +// aplapplist.cpp +// + +#include "aplapplist.h" +#include "APGAPLST.H" // KDefaultAppIconMbm +#include "aplapplistitem.h" +#include "../apgrfx/APGSTD.H" // EPanicNullPointer +#include "APFDEF.H" +#include "../apparc/TRACE.H" +#include "apgnotif.h" // MApaAppListServObserver +#include "aplappregfinder.h" // CApaAppRegFinder +#include // BaflUtils::NearestLanguageFile() +#include // RBufWriteStream +#include "aplappinforeader.h" +#include "apsiconcaptionoverride.h" +#ifdef SYMBIAN_BAFL_SYSUTIL +#include +#endif + + +// Delays in the pseudo idle object that builds the application list +// + +const TInt KIdleStartDelay=0; +const TInt KBufferExpansionGranularity = 0x100; +const TInt KNumberOfIconsInDefaultMbm = 3; +const TInt KAppListToFileStartDelay = 60000000; +#ifdef SYMBIAN_BAFL_SYSUTIL +const TInt KInfoBufLength=KSysUtilVersionTextLength; +//This file is used for storing the rom version. If actual rom version differs from the one stored here the applist is not restored. +//This file is versioned to avoid a data compatability break on adding further information to this file. +//On adding further info to this file, KROMVersionCacheFileMajorVersion or KROMVersionCacheFileMinorVersion or KROMVersionCacheFileBuildVersion needs to be incremented appropriately. +_LIT(KROMVersionStringCacheFileName, "ROMVersionCache.bin"); +const TInt8 KROMVersionCacheFileMajorVersion=1; +const TInt8 KROMVersionCacheFileMinorVersion=0; +const TInt16 KROMVersionCacheFileBuildVersion=0; +#endif + + +GLDEF_C void Panic(TApgPanic aPanic) + { + _LIT(KApGrfxPanic,"APGRFX"); + User::Panic(KApGrfxPanic,aPanic); + } + + +// +// Class CApaLangChangeMonitor +// + +/** +Utility class used to monitor locale/language change event. +@internalComponent +*/ +NONSHARABLE_CLASS(CApaAppList::CApaLangChangeMonitor) : public CActive + { +public: + static CApaLangChangeMonitor* NewL(CApaAppList& aAppList); + ~CApaLangChangeMonitor(); + void Start(); +private: + CApaLangChangeMonitor(CApaAppList& aAppList); + void ConstructL(); +private: //from CActive + void RunL(); + void DoCancel(); + TInt RunError(TInt aError); +private: + RChangeNotifier iLangNotifier; + CApaAppList& iAppList; + TLanguage iPrevLanguage; + }; + + +// +// Local functions +// + +void CleanupServiceArray(TAny* aServiceArray) + { + __ASSERT_DEBUG(aServiceArray, Panic(EPanicNullPointer)); + CArrayFixFlat* serviceArray = static_cast*>(aServiceArray); + const TInt serviceCount = serviceArray->Count(); + + for (TInt i = serviceCount - 1; i >= 0; i--) + (*serviceArray)[i].Release(); + + delete serviceArray; + serviceArray = 0; + } + + +// +// Class CApaAppList +// + +EXPORT_C CApaAppList* CApaAppList::NewL(RFs& aFs, TBool aLoadMbmIconsOnDemand, TInt aIdlePeriodicDelay) + { + CApaAppList* self=new (ELeave) CApaAppList(aFs, aLoadMbmIconsOnDemand, aIdlePeriodicDelay); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CApaAppList::CApaAppList(RFs& aFs, TBool aLoadMbmIconsOnDemand, TInt aIdlePeriodicDelay) + :iFs(aFs), + iFlags(0), + iIdlePeriodicDelay(aIdlePeriodicDelay), + iLoadMbmIconsOnDemand(aLoadMbmIconsOnDemand), + iUninstalledApps(NULL) + { + } + +void CApaAppList::ConstructL() + { + iAppRegFinder = CApaAppRegFinder::NewL(iFs); + + User::LeaveIfError(iFsShareProtected.Connect()); + User::LeaveIfError(iFsShareProtected.ShareProtected()); + User::LeaveIfError(Dll::SetTls(this)); + + //Start language change monitor. + iAppLangMonitor = CApaLangChangeMonitor::NewL(*this); + const TInt KArrayGranularity = 128; + iForcedRegistrations = new (ELeave) CDesCArraySeg(KArrayGranularity); + + // Init the AppsList cache paths + _LIT(KAppsListCacheFileName, ":\\private\\10003a3f\\AppsListCache\\AppsList.bin"); + _LIT(KAppsListCacheBackUpFileName, ":\\private\\10003a3f\\AppsListCache\\AppsList_Backup.bin"); + _LIT(KAppsListCachePath, ":\\private\\10003a3f\\AppsListCache\\"); + + const TChar sysDrive = RFs::GetSystemDriveChar(); + TInt maxSizeofFileName = KAppsListCacheFileName().Length() + 1; + iAppsListCacheFileName.CreateL(maxSizeofFileName); + iAppsListCacheFileName.Append(sysDrive); + iAppsListCacheFileName.Append(KAppsListCacheFileName()); + + maxSizeofFileName = KAppsListCacheBackUpFileName().Length() + 1; + iAppsListCacheBackUpFileName.CreateL(maxSizeofFileName); + iAppsListCacheBackUpFileName.Append(sysDrive); + iAppsListCacheBackUpFileName.Append(KAppsListCacheBackUpFileName()); + + maxSizeofFileName = KAppsListCachePath().Length() + 1; + iAppsListCachePath.CreateL(maxSizeofFileName); + iAppsListCachePath.Append(sysDrive); + iAppsListCachePath.Append(KAppsListCachePath()); + + iIconCaptionOverrides = new(ELeave) CApaIconCaptionOverrides(); + iIconCaptionObserver = CApaIconCaptionCenrepObserver::NewL(*iIconCaptionOverrides); + iIconCaptionObserver->LoadOverridesL(); + } + +EXPORT_C CApaAppList::~CApaAppList() +/** Frees all resources prior to destruction, including the application data list. */ + { + iValidFirstAppData = NULL; + DeleteAppData(); + + iAppData = NULL; + iObserver = NULL; + iFsShareProtected.Close(); + + delete iDefaultIconArray; + delete iDefaultAppIconMbmFileName; + delete iAppRegFinder; + delete iAppIdler; + delete iAppListStorer; + delete iAppIconLoader; + delete iAppLangMonitor; + delete iForcedRegistrations; + delete iIconCaptionObserver; + delete iIconCaptionOverrides; + iAppsListCacheFileName.Close(); + iAppsListCacheBackUpFileName.Close(); + iAppsListCachePath.Close(); + + iCustomAppList.ResetAndDestroy(); + iCustomAppList.Close(); + } + +// Stop scanning applications if installation or uninstallation has started +EXPORT_C void CApaAppList::StopScan(TBool aNNAInstall) + { + if (aNNAInstall) + { + iNNAInstallation = ETrue; + } + if (iAppIdler) + { + delete iAppIdler; + iAppIdler=NULL; + } + UndoSetPending(iAppData); + } + +// Allow scanning when installation or uninstallation is complete +EXPORT_C void CApaAppList::RestartScanL() + { + TRAP_IGNORE(PurgeL()); + StartIdleUpdateL(); + } + +EXPORT_C TBool CApaAppList::AppListUpdatePending() + { + return iNNAInstallation; + } + +void CApaAppList::UndoSetPending(CApaAppData* aAppData) + // Reset all apps to pevious pending state so they don't get purged + { + for (; aAppData; aAppData = aAppData->iNext) + { + if (aAppData->iIsPresent == CApaAppData::EPresentPendingUpdate) + { + aAppData->iIsPresent = CApaAppData::EIsPresent; + } + } + } + +EXPORT_C void CApaAppList::StartIdleUpdateL() +/** Updates the list asynchronously, using an idle time active object, +and no observer. When the update is finished, the resulting app +list is stored. */ + { + // find the default icons (.mbm file) for applications, wrt current locale + CreateDefaultAppIconFileNameL(); + + // File operation is abandoned if it is in progress. + if (iAppListStorer && iAppListStorer->IsActive()) + { + delete iAppListStorer; + iAppListStorer = NULL; + } + + // Stops icon loading if it is in progress. + if (iAppIconLoader && iAppIconLoader->IsActive()) + { + delete iAppIconLoader; + iAppIconLoader = NULL; + } + + // DEF076594 - if changing locale, need to update the default icons here + // If updating the default icons array fails, the array is left in the state + // it was in before the call. + if(iDefaultIconArray) + { + TRAP_IGNORE(UpdateDefaultIconsL()); + } + + // start to scan. + if (iAppIdler) + { + delete iAppIdler; + iAppIdler=NULL; + } + + // DEF072701 + // When performing the update scan let the idle object have lower priority. + if (IsFirstScanComplete()) + { + iAppIdler=CPeriodic::NewL(CActive::EPriorityLow); + } + else + { + iAppIdler=CPeriodic::NewL(CActive::EPriorityStandard); + } + SetPending(iAppData); + iAppRegFinder->FindAllAppsL(CApaAppRegFinder::EScanAllDrives); + + // DEF072701 + // If this is the first scan i.e the boot scan then it may take some time. Thus + // the periodic delay value should be used so that this process will stop periodically + // to allow time for other processes. + // If this is just a re-scan it should take much less time. Therefore it should just + // be completed in one go rather than periodically delayed. Thus the delay value + // should be set to 0. + iAppIdler->Start(KIdleStartDelay, IsFirstScanComplete()? 0 : iIdlePeriodicDelay, TCallBack(IdleUpdateCallbackL, this)); + } + +EXPORT_C void CApaAppList::StartIdleUpdateL(MApaAppListObserver* aObserver) +/** Updates the list asynchronously, using an idle time active object +and an observer. When the update is finished, the resulting app list +is stored and the observer is notified with an MApaAppListServObserver::EAppListChanged +message, if the list changed. +@param aObserver Observer to be notified when the update has finished. */ + { + iObserver=aObserver; + + // Rename Appslist.bin file to AppsList_Backup.bin, so that it can be renamed back, if rescan/update scan does not change applist. + TInt replaceError = iFs.Replace(iAppsListCacheFileName, iAppsListCacheBackUpFileName); + if (replaceError != KErrNone) + { + iFs.Delete(iAppsListCacheFileName); + } + StartIdleUpdateL(); + } + +void CApaAppList::CreateDefaultAppIconFileNameL() + { + TFileName tempFileName(KDefaultAppIconMbm); + TLanguage language; + BaflUtils::NearestLanguageFileV2(iFs, tempFileName, language); + (void)language; + delete iDefaultAppIconMbmFileName; + iDefaultAppIconMbmFileName = NULL; + iDefaultAppIconMbmFileName = tempFileName.AllocL(); + } + +EXPORT_C void CApaAppList::InitListL(MApaAppListObserver* aObserver) +/** It Restores the data present in the AppsList.bin file and updates the applist. + * If Restore operation fails then it + * starts updating the list asynchronously, by calling StartIdleUpdateL(). + +@param aObserver Observer to be notified when the update has finished. */ + { + DeleteAppsListBackUpAndTempFiles(); + TInt ret = KErrGeneral; +#ifndef __WINS__ // on the emulator, don't read app list from file, as doing so means apps + // built while the emulator isn't running won't appear in the list + TRAP(ret, RestoreL()); +#endif + if (ret != KErrNone) + { + // There was an error during restore, so update the list asynchronously. + DeleteAppData(); + iFs.Delete(iAppsListCacheFileName); + StartIdleUpdateL(aObserver); + } + else + { + iObserver = aObserver; + if (iLoadMbmIconsOnDemand) + { + InitiateStoringOfAppList(); + } + else + { + StartIconLoadingL(); + } + } + } + +void CApaAppList::StartIconLoadingL() + { + iAppIconLoader = new(ELeave) CApaIdleIconLoader(iAppData, iFs, *this); + iAppIconLoader->Start(); + } + +void CApaAppList::ScanRemovableDrivesAndUpdateL() +/** Rename Appslist.bin file to AppsList_Backup.bin, so that it can be renamed back, + if the update scan on removable media drives does not change applist. */ + { + const TArray listOfRemovableMediaDrives = iAppRegFinder->DriveList(); + const TInt count = listOfRemovableMediaDrives.Count(); + + // Removable media scan would take place only if removable drives are present. + if (count) + { + CApaAppData* appData = iAppData; + while (appData) + { + for (TInt driveIndex = 0; driveIndex < count; ++driveIndex) + { + if (TParsePtrC(*appData->iRegistrationFile).Drive() == listOfRemovableMediaDrives[driveIndex].iUnit.Name()) + { + appData->SetAppPending(); + break; + } + } + appData = appData->iNext; + } + + while (IdleUpdateL()) + { // It updates the removable media apps present in AppList if it has changed. + + }; + } + } + +void CApaAppList::DeleteAppsListBackUpAndTempFiles() +/** Deletes all files inside AppsListCache folder except AppsList.bin */ + { + _LIT(KTemp, "AppsList.bin"); + CDir* cache = NULL; + TInt ret = iFs.GetDir(iAppsListCachePath, KEntryAttNormal, ESortNone, cache); + if (ret == KErrNone) + { + const TInt count = cache->Count(); + TBufC cacheFileName; + TEntry entry; + for (TInt i = 0; i < count; ++i) + { + entry=(*cache)[i]; + cacheFileName=entry.iName; + #if defined (SYMBIAN_BAFL_SYSUTIL) + if ((cacheFileName.Match(KTemp) == KErrNotFound) && (cacheFileName.Match(KROMVersionStringCacheFileName) == KErrNotFound)) + #else + if ((cacheFileName.Match(KTemp) == KErrNotFound)) + #endif + { + TFileName fileNameToDelete; + fileNameToDelete.Append(iAppsListCachePath); + fileNameToDelete.Append(cacheFileName); + iFs.Delete(fileNameToDelete); + } + } + delete cache; + } + } + +void CApaAppList::RestoreL() +/** It restores the data present in the AppsList.bin file */ + { + RFileReadStream theReadStream; + User::LeaveIfError(theReadStream.Open(iFs, iAppsListCacheFileName, EFileRead)); + CleanupClosePushL(theReadStream); + + TLanguage appListFileLanguage = (TLanguage)theReadStream.ReadInt32L(); + if (appListFileLanguage != User::Language()) + { + User::Leave(KErrNotSupported); + } + +#if defined (SYMBIAN_BAFL_SYSUTIL) + //Build the filename for the cache file + TInt maxSizeofFileName = iAppsListCachePath.Length() + KROMVersionStringCacheFileName().Length(); + RBuf romVersionCacheFileName; + romVersionCacheFileName.CreateL(maxSizeofFileName); + romVersionCacheFileName.CleanupClosePushL(); + romVersionCacheFileName.Append(iAppsListCachePath); + romVersionCacheFileName.Append(KROMVersionStringCacheFileName()); + + RFileReadStream romVerStream; + User::LeaveIfError(romVerStream.Open(iFs,romVersionCacheFileName,EFileRead)); + CleanupClosePushL(romVerStream); + + TVersion actualROMVersionCacheFileVersion(KROMVersionCacheFileMajorVersion, KROMVersionCacheFileMinorVersion, KROMVersionCacheFileBuildVersion); + TVersionName actualROMVersionCacheFileVersionName = actualROMVersionCacheFileVersion.Name(); + + //read the rom file version + TInt8 romVersionCacheFileMajorVersion = romVerStream.ReadInt8L(); + TInt8 romVersionCacheFileMinorVersion = romVerStream.ReadInt8L(); + TInt16 romVersionCacheFileBuildVersion = romVerStream.ReadInt16L(); + TVersion romVersionCacheFileVersion(romVersionCacheFileMajorVersion, romVersionCacheFileMinorVersion, romVersionCacheFileBuildVersion); + TVersionName romVersionCacheFileVersionName = romVersionCacheFileVersion.Name(); + + //If persisted file version differs from what apparc can handle, recreate rom version file and applist.bin + if (romVersionCacheFileVersionName.Compare(actualROMVersionCacheFileVersionName) != 0) + { + User::Leave(KErrGeneral); + } + + //Read the length & value of software version from it. + TBuf softwareVersion; + TUint32 length = romVerStream.ReadUint32L(); + if (length>KInfoBufLength) + { + //File must be corrupt, an attempt to read will panic + User::Leave(KErrCorrupt); + } + romVerStream.ReadL(softwareVersion, length); + + //the persisted version has been successfully read + //read the actual current version string + TBuf actualSoftwareVersion; + TInt err = SysUtil::GetSWVersion(actualSoftwareVersion); //use the SysUtil implementation + if(err == KErrNone) + { + if (softwareVersion.Compare(actualSoftwareVersion) != 0) + { + //Leave if the current version is different from the previous stored version and recreate applist. +#ifdef _DEBUG + RDebug::Print(_L("!!Firmware update detected!! Rebuilding AppList")); +#endif + User::Leave(KErrGeneral); + } + } + else + { + //Leave if any error reading the version information, except if file is not present + if (err != KErrPathNotFound && err != KErrNotFound) + { +#ifdef _DEBUG + RDebug::Print(_L("!!Error %d reading Firmware version. Rebuilding AppList"),err); +#endif + User::Leave(err); + } + } + CleanupStack::PopAndDestroy(2); //romVerStream, romVersionCacheFileName +#endif + + // Create Default Icon File Name + CreateDefaultAppIconFileNameL(); + + TInt ret = KErrNone; + while (ret == KErrNone) + { + CApaAppData* const pApp = new (ELeave) CApaAppData(iFs); + CleanupStack::PushL(pApp); + + // Restore entries till we leave + TRAP(ret, pApp->InternalizeL(theReadStream)); + + if (ret != KErrNone && ret != KErrEof) + { + User::Leave(ret); + } + // Check that the app has not been added to the list twice + if (ret == KErrNone && !AppDataByUid(pApp->iUidType[2])) + { + AddToList(pApp); + CleanupStack::Pop(pApp); + } + else + { // Delete pApp if an End of File condition is reached or the app has been added to the list twice + CleanupStack::PopAndDestroy(pApp); + } + } + // Close the stream; + CleanupStack::PopAndDestroy(&theReadStream); + + iFs.Rename(iAppsListCacheFileName, iAppsListCacheBackUpFileName); + iAppRegFinder->FindAllAppsL(CApaAppRegFinder::EScanRemovableDrives); // Builds the Removable Media Drive List + + iFlags |= ENotifyUpdateOnFirstScanComplete; + + // It runs an update scan on removable media apps. + ScanRemovableDrivesAndUpdateL(); + } + +EXPORT_C TBool CApaAppList::IsLanguageChangePending() const +/** Returns ETrue if a language change event is received and a re-scan is in progress otherwise EFalse. */ + { + return (iFlags & ELangChangePending); + } + + +TInt CApaAppList::IdleUpdateCallbackL(TAny* aObject) + { + CApaAppList* self=REINTERPRET_CAST(CApaAppList*,aObject); + const TBool moreToCome=self->IdleUpdateL(); + if (moreToCome==EFalse) + { + //Reset language change flag if scanning is over. + if (self->IsLanguageChangePending()) + self->iFlags &= ~ELangChangePending; + + self->StopIdler(); + if (self->iLoadMbmIconsOnDemand) + { + self->InitiateStoringOfAppList(); + } + else + { + self->StartIconLoadingL(); + } + } + return moreToCome; + } + +void CApaAppList::StoreL() + { + iAppListStorer = CApaAppListStorer::NewL(iAppData, iFs, *this); + iAppListStorer->StartL(KAppListToFileStartDelay); + } + +void CApaAppList::NotifyObserver() + { + if (iObserver) + { + if (iFlags & EAppListHasChanged || iFlags & ENotifyUpdateOnFirstScanComplete) + iObserver->NotifyUpdate(MApaAppListServObserver::EAppListChanged); // NotifyUpdate will notify clients for both list update and scan complete. + else + iObserver->NotifyScanComplete(); // NotifyScanComplete will notify clients for scan complete. + + iObserver=NULL; + } + } + +void CApaAppList::StopIdler() + { + delete iAppIdler; + iAppIdler=NULL; + } + +TInt CApaAppList::IdleUpdateL() +// returns ETrue if there is more scanning to be done. + { + TBool more=EFalse; + TApaAppEntry currentApp = TApaAppEntry(); + TRAPD(err, more = iAppRegFinder->NextL(currentApp, *iForcedRegistrations)); + if (err!=KErrNone) + { + if (iFlags & ENotifyUpdateOnFirstScanComplete) + User::Leave(err); + + return more; + } + TBool hasChanged=EFalse; + if (more) + { + TRAPD(err,UpdateNextAppL(currentApp,hasChanged)); + if (err!=KErrNone) + { + SetNotFound(iAppData,hasChanged); + if (iFlags & ENotifyUpdateOnFirstScanComplete) + User::Leave(err); + + more=EFalse; // abandon ship + } + } + else + { + SetNotFound(iAppData,hasChanged); + PurgeL(); + } + + if (hasChanged) + iFlags |= EAppListHasChanged; + + return more; + } + +EXPORT_C TBool CApaAppList::IsIdleUpdateComplete() const +/** Tests whether an asynchronous update of the list is currently in progress. + +@return True if no asynchronous update of the list is currently in progress, +otherwise false. */ + { + return iAppIdler == NULL; + } + +void CApaAppList::SetPending(CApaAppData* aAppData) + // set all apps to pending update - we'll find them again as we scan + { + for (; aAppData; aAppData = aAppData->iNext) + aAppData->SetAppPending(); + } + +void CApaAppList::SetNotFound(CApaAppData* aAppData, TBool& aHasChanged) + // mark any unfound apps not present + { + while (aAppData) + { + if (aAppData->IsPending()) + { + aAppData->iIsPresent = CApaAppData::ENotPresent; + aHasChanged = ETrue; + } + aAppData = aAppData->iNext; + } + } + +void CApaAppList::AddToList( CApaAppData* aAppData ) + { + __ASSERT_DEBUG(aAppData, Panic(EPanicNullPointer)); + aAppData->iNext=iAppData; + iAppData=aAppData; + } + +void CApaAppList::UpdateNextAppL(const TApaAppEntry& aAppEntry,TBool& aHasChanged) + { + CApaAppData* appData=AppDataByUid(aAppEntry.iUidType[2]); + if (appData==NULL) + {// not in list, so add it at the start + TRAPD(err,appData=CApaAppData::NewL(aAppEntry, iFs)); + if (err==KErrNone) + { + AddToList( appData ); + aHasChanged=ETrue; + } + } + else if (appData->IsPending()) + { // not found yet during current scan - we may need to override this one + + // On a system which scans for registration .RSC files (V2 apps) first, followed by + // .APP files (V1 apps), it's valid for a V1 app to override a V2 app (if the V2 app + // has just been removed). If this is the case, assume it's ok to compare the V1 .APP filename, + // with the V2 .RSC filename as their filenames will never match (which is what we want in this case). + TPtrC currentFileName; + if (appData->RegistrationFileUsed()) + currentFileName.Set(*appData->iRegistrationFile); + else + currentFileName.Set(*appData->iFullName); + + if (aAppEntry.iFullName.CompareF(currentFileName)!=0) + { + delete appData->iSuccessor; + appData->iSuccessor = NULL; + appData->iSuccessor = CApaAppEntry::NewL(aAppEntry); + + appData->iIsPresent = CApaAppData::ESuperseded; + aHasChanged=ETrue; + } + else + { + if (appData->Update() || appData->iIsPresent==CApaAppData::ENotPresentPendingUpdate) + aHasChanged=ETrue; + + appData->iIsPresent = CApaAppData::EIsPresent; + } + } + } + +/** +@internalComponent +*/ +EXPORT_C CApaAppData* CApaAppList::FindAndAddSpecificAppL(CApaAppRegFinder* aFinder, TUid aAppUid) + { +//Scans and adds the specified application to the app list if found + __ASSERT_DEBUG(aFinder, Panic(EPanicNullPointer)); + TBool found = EFalse; + TApaAppEntry appEntry; + aFinder->FindAllAppsL(CApaAppRegFinder::EScanAllDrives); + while (aFinder->NextL(appEntry, *iForcedRegistrations)) + { + if (appEntry.iUidType[2] == aAppUid) + { + found = ETrue; + break; + } + } + + CApaAppData* app = NULL; + if (found) + { + // add the app to the list + TBool hasChanged = EFalse; + CApaAppData* prevFirstAppInList = iAppData; + UpdateNextAppL(appEntry, hasChanged); + if (iAppData != prevFirstAppInList) + app = iAppData; // assume the new app was added to the list + + if (hasChanged) + iFlags |= EAppListHasChanged; + } + + return app; + } + +EXPORT_C void CApaAppList::PurgeL() +/** Removes any applications from the list if they are no longer present +on the phone. It updates applications that have been +superceded. */ + { + CApaAppData* appData=iAppData; + CApaAppData* prev=NULL; + while (appData) + { + CApaAppData* next=appData->iNext; + if (appData->iIsPresent==CApaAppData::ENotPresent) + { + if (prev) + prev->iNext=next; + else + iAppData=next; + + //Add uninstalled application UID to a list + if(iUninstalledApps==NULL) + iUninstalledApps=new(ELeave) CArrayFixFlat(1); + + iUninstalledApps->AppendL(appData->AppEntry().iUidType[2]); + + delete appData; + } + else if (appData->iIsPresent==CApaAppData::ESuperseded) + { + CApaAppData* newApp=NULL; + TApaAppEntry appEntry; + appData->iSuccessor->Get(appEntry); + TRAPD(err,newApp=CApaAppData::NewL(appEntry, iFs)); + if (err==KErrNone) + { + // remove the old one and add the new one in its place + if (prev) + prev->iNext=newApp; + else + iAppData=newApp; + + newApp->iNext = appData->iNext; + delete appData; + // increment the iterator + prev = newApp; + } + } + else + prev=appData; + + appData=next; + } + } + +EXPORT_C TInt CApaAppList::Count() const +/** Gets the count of applications present in the app list. + +@return The number of applications in the list. */ + + { + TInt count=0; + CApaAppData* appData=iAppData; + while (appData) + { + count++; + appData=appData->iNext; + } + + return count; + } + +EXPORT_C CApaAppData* CApaAppList::FirstApp() const +/** Gets a pointer to the first application in the list +that can use the default screen mode. + +@return A pointer to the first application. */ + { + return FirstApp(0); + } + +EXPORT_C CApaAppData* CApaAppList::FirstApp(TInt aScreenMode) const +/** Gets a pointer to the first application in the list +that can use the specified screen mode. + +@param aScreenMode The index of the screen mode. Specifying +KIgnoreScreenMode returns the first application in the list, +regardless of screen mode. +@return A pointer to the first application that can use the +specified screen mode. */ + { + + CApaAppData* appData=iValidFirstAppData; + + if(aScreenMode!=KIgnoreScreenMode) + { + while (appData && !appData->CanUseScreenMode(aScreenMode)) + appData = appData->iNext; + } + + return appData; + } + +EXPORT_C CApaAppData* CApaAppList::NextApp(const CApaAppData* aApp) const +/** Gets a pointer to the next application after aApp in the list +that can use the default screen mode. + +@param aApp A pointer to an application in the list. +@return A pointer to the next application after aApp in the list +that can use the default screen mode. +@panic APGRFX 12 aApp is NULL. */ + { + return NextApp(aApp,0); + } + +EXPORT_C CApaAppData* CApaAppList::NextApp(const CApaAppData* aApp, TInt aScreenMode) const +/** Gets a pointer to the next application after aApp in the list +that can use the specified screen mode. + +@param aApp A pointer to an application in the list. +@param aScreenMode The index of the screen mode. Specifying +KIgnoreScreenMode returns the next application in the list, +regardless of screen mode. +@return A pointer to the next application after aApp in the list +that can use the specified screen mode. +@panic APGRFX 12 aApp is NULL. */ + + { + __ASSERT_ALWAYS(aApp,Panic(EPanicNoAppDataSupplied)); + // + CApaAppData* iApp=aApp->iNext; //lint !e613 Suppress possible use of null pointer - asserted above + + if(aScreenMode!=KIgnoreScreenMode) + while (iApp && !iApp->CanUseScreenMode(aScreenMode)) + iApp = iApp->iNext; + + return iApp; + } + +EXPORT_C CApaAppData* CApaAppList::AppDataByUid(TUid aAppUid) const +/** Gets a pointer to the application in the list whose third +UID matches the specified UID. + +@param aAppUid An application's third UID. +@return A pointer to the application, if successful. Null, +if no match is found or if KNullUid was specified. */ + { + if (aAppUid==KNullUid) + return NULL; // never match null UID as it represents an un-UIDed file + + CApaAppData* appData=iAppData; + while (appData) + { + if (appData->AppEntry().iUidType[2]==aAppUid) + return appData; + appData=appData->iNext; + } + + return NULL; + } + +EXPORT_C CApaAppData* CApaAppList::AppDataByFileName(const TDesC& aFullFileName) const +/** Gets a pointer to the application in the list whose application +file name matches the one specified + +@param aFullFileName a file name. +@return A pointer to the application, if successful. Null, +if no match is found or if KNullDesC was specified. +@internalTechnology +*/ + { + if (aFullFileName.Length()==0) + return NULL; // never match null UID as it represents an un-UIDed file + + CApaAppData* appData=iAppData; + while (appData) + { + if (appData->AppEntry().iFullName.CompareF(aFullFileName)==0) + return appData; + + appData=appData->iNext; + } + + return NULL; + } + +/** +Adds a registration file to the iForcedRegistrations array. + +@param aRegistrationFile The function takes ownership of the HBufC. +@internalComponent +*/ +EXPORT_C void CApaAppList::AddForcedRegistrationL(const TDesC& aRegistrationFile) + { + TInt err = iForcedRegistrations->InsertIsqL(aRegistrationFile, ECmpFolded); + if (err != KErrAlreadyExists) // We silently ignore attempts to insert duplicates + User::LeaveIfError(err); + + } //lint !e818 Suppress pointer parameter 'aRegistrationFile' could be declared as pointing to const + +EXPORT_C void CApaAppList::ResetForcedRegistrations() + { + if(iForcedRegistrations) + iForcedRegistrations->Reset(); + } + +/** Finds the preferred application to handle the specified data type. + +@param aDataType The data type of interest. +@return The third UID of the application in the list which has the +highest priority for handling the specified data type. A null UID is +returned if no application in the list can handle the specified data type. */ +EXPORT_C TUid CApaAppList::PreferredDataHandlerL(const TDataType& aDataType) const + { + TInt dummy; + return PreferredDataHandlerL(aDataType, NULL, dummy); + } + +/** Finds the preferred application to handle the specified data type. + +@param aDataType The data type of interest. +@param aServiceUid The optional service UID. +@param aPriority The priority associated with the returned app. +@return The third UID of the application in the list which has the +highest priority for handling a combination of the specified data type +and service. A null UID is returned if no application in the list can +handle the combination of specified data type and service. +@internalComponent +*/ +EXPORT_C TUid CApaAppList::PreferredDataHandlerL(const TDataType& aDataType, const TUid* aServiceUid, TInt& aPriority) const + { + // If there is a service UID then first try to use the service specific list + // of datatypes + if (aServiceUid) + { + CApaAppData* appData = iAppData; + aPriority = KDataTypePriorityNotSupported; + TUid uid = KNullUid; + + while (appData) + { + TInt priority = appData->ImplementsServiceWithDataType(*aServiceUid, aDataType); + if (priority > aPriority) + { + aPriority=priority; + uid=appData->AppEntry().iUidType[2]; + } + + appData=appData->iNext; + } + + if (aPriority != KDataTypePriorityNotSupported) + return uid; + } + + CApaAppData* appData = iAppData; + aPriority = KDataTypePriorityNotSupported; + TUid uid = KNullUid; + + // Run through all of the linked list of app-data to locate the application + // with the highest priority that can handle the given data type + while (appData) + { + const TInt priority = appData->DataType(aDataType); + if ((priority > aPriority) && (!aServiceUid || (aServiceUid && appData->ImplementsService(*aServiceUid)))) + { + aPriority = priority; + uid = appData->AppEntry().iUidType[2]; + } + + appData=appData->iNext; + } + + return uid; + } + +void CApaAppList::DeleteAppData() + { + iValidFirstAppData = NULL; + iFlags &= ~EFirstScanComplete; + iFlags &= ~EAppListHasChanged; + iFlags &= ~ELangChangePending; + + CApaAppData* next = NULL; + for (CApaAppData* appData=iAppData; appData; appData = next) + { + next = appData->iNext; + delete appData; + } + iAppData = NULL; + } + +void CApaAppList::ScanComplete() + { + if (!(iFlags & EFirstScanComplete) && iObserver) + iObserver->InitialListPopulationComplete(); + iValidFirstAppData = iAppData; + iFlags|=EFirstScanComplete; + iNNAInstallation = EFalse; + } + +/** + * + * Tests whether the first scan for list of Apps has completed. + * + * @return "TBool" + * True, if the first scan for list of Apps has completed; false, otherwise. + * @internalComponent + */ +EXPORT_C TBool CApaAppList::IsFirstScanComplete() const + { + return iFlags&EFirstScanComplete; + } + +EXPORT_C TBool CApaAppList::AppScanInProgress() const +/** @internalComponent */ + { + return (iAppIdler!=NULL) && iAppIdler->IsActive(); + } + +/** +@internalComponent +*/ +EXPORT_C CBufFlat* CApaAppList::ServiceArrayBufferL(TUid aAppUid) const + { + CApaAppData* app = FirstApp(KIgnoreScreenMode); + while (app && app->AppEntry().iUidType[2] != aAppUid) + app = NextApp(app, KIgnoreScreenMode); + + if (app) + { + if (!app->RegistrationFileUsed()) + User::Leave(KErrNotSupported); + + if (app->iServiceArray) + { + CBufFlat* const buf = CBufFlat::NewL(KBufferExpansionGranularity); + CleanupStack::PushL(buf); + RBufWriteStream writeStream(*buf); + writeStream << *(app->iServiceArray); + writeStream.CommitL(); + writeStream.Release(); + CleanupStack::Pop(buf); + return buf; + } + } + + User::Leave(KErrNotFound); + return NULL; // to keep compiler happy + } + +/** +@internalComponent +*/ +EXPORT_C CBufFlat* CApaAppList::ServiceUidBufferL(TUid aAppUid) const + { + CApaAppData* app = FirstApp(KIgnoreScreenMode); + while (app && app->AppEntry().iUidType[2] != aAppUid) + app = NextApp(app, KIgnoreScreenMode); + + if (app) + { + if (!app->RegistrationFileUsed()) + User::Leave(KErrNotSupported); + + if (app->iServiceArray) + { + CArrayFixFlat& serviceArray = *(app->iServiceArray); + CArrayFixFlat* uidArray = new(ELeave) CArrayFixFlat(4); + CleanupStack::PushL(uidArray); + for (TInt i = serviceArray.Count()-1; i >= 0; i--) + uidArray->AppendL(serviceArray[i].Uid()); + + CBufFlat* const buf = CBufFlat::NewL(KBufferExpansionGranularity); + CleanupStack::PushL(buf); + RBufWriteStream writeStream(*buf); + writeStream << *uidArray; + writeStream.CommitL(); + writeStream.Release(); + CleanupStack::Pop(buf); + CleanupStack::PopAndDestroy(uidArray); + return buf; + } + } + + User::Leave(KErrNotFound); + return NULL; // to keep compiler happy + } + +/** +@internalComponent +*/ +EXPORT_C CBufFlat* CApaAppList::ServiceOpaqueDataBufferL(TUid aAppUid, TUid aServiceUid) const + { + CApaAppData* app = FirstApp(KIgnoreScreenMode); + while (app && app->AppEntry().iUidType[2] != aAppUid) + app = NextApp(app, KIgnoreScreenMode); + + if (app) + { + if (!app->RegistrationFileUsed()) + User::Leave(KErrNotSupported); + + if (app->iServiceArray) + { + CArrayFixFlat* implArray = NULL; + CArrayFixFlat& serviceArray = *(app->iServiceArray); + for (TInt i = serviceArray.Count()-1; i >= 0; i--) + { + const TApaAppServiceInfo& infoRef = serviceArray[i]; + if (infoRef.Uid() == aServiceUid) + { + if (!implArray) + { + implArray = new(ELeave) CArrayFixFlat(4); + CleanupStack::PushL(TCleanupItem(CleanupServiceArray, implArray)); + } + + CArrayFixFlat* dummy = new(ELeave) CArrayFixFlat(1); + CleanupStack::PushL(dummy); + TApaAppServiceInfo info(aServiceUid, dummy, infoRef.OpaqueData().AllocLC()); + implArray->AppendL(info); + CleanupStack::Pop(CONST_CAST(TDesC8*,&info.OpaqueData())); + CleanupStack::Pop(dummy); + } + } + + if (implArray) + { + CBufFlat* const buf = CBufFlat::NewL(KBufferExpansionGranularity); + CleanupStack::PushL(buf); + RBufWriteStream writeStream(*buf); + writeStream << *implArray; + writeStream.CommitL(); + writeStream.Release(); + CleanupStack::Pop(buf); + CleanupStack::PopAndDestroy(implArray); + return buf; + } + } + } + User::Leave(KErrNotFound); + return NULL; // to keep compiler happy + } + +/** +@internalComponent +*/ +EXPORT_C CBufFlat* CApaAppList::ServiceImplArrayBufferL(TUid aServiceUid) const + { + CApaAppData* app = FirstApp(KIgnoreScreenMode); + // build an array containing all implementations of the service identified by aServiceUid + CArrayFixFlat* implArray = NULL; + while (app) + { + if (app->iServiceArray) + { + for (TInt i = app->iServiceArray->Count()-1; i >= 0; i--) + { + const TApaAppServiceInfo& infoRef = (*app->iServiceArray)[i]; + if (infoRef.Uid() == aServiceUid) + { + if (!implArray) + { + implArray = new(ELeave) CArrayFixFlat(4); + CleanupStack::PushL(TCleanupItem(CleanupServiceArray, implArray)); + } + + CArrayFixFlat* datatypes = DataTypeArrayDeepCopyLC(infoRef.DataTypes()); + HBufC8* data = infoRef.OpaqueData().AllocLC(); + TApaAppServiceInfo info(app->AppEntry().iUidType[2], datatypes, data); + implArray->AppendL(info); + CleanupStack::Pop(data); + CleanupStack::Pop(datatypes); + } + } + } + app = NextApp(app, KIgnoreScreenMode); + } + + if (implArray) + { + CBufFlat* const buf = CBufFlat::NewL(KBufferExpansionGranularity); + CleanupStack::PushL(buf); + RBufWriteStream writeStream(*buf); + writeStream << *(implArray); + writeStream.CommitL(); + writeStream.Release(); + CleanupStack::Pop(buf); + CleanupStack::PopAndDestroy(implArray); + return buf; + } + + User::Leave(KErrNotFound); + return NULL; // to keep compiler happy + } + +EXPORT_C CBufFlat* CApaAppList::ServiceImplArrayBufferL(TUid aServiceUid, const TDataType& aDataType) const + { + CApaAppData* app = FirstApp(KIgnoreScreenMode); + // build an array containing all implementations of the service identified by aServiceUid + CArrayFixFlat* implArray = NULL; + while (app) + { + if (app->iServiceArray) + { + for (TInt i = app->iServiceArray->Count()-1; i >= 0; i--) + { + const TApaAppServiceInfo& infoRef = (*app->iServiceArray)[i]; + if (infoRef.Uid() == aServiceUid) + { + if (KDataTypePriorityNotSupported != app->DataType(aDataType, infoRef.DataTypes())) + { + if (!implArray) + { + implArray = new(ELeave) CArrayFixFlat(4); + CleanupStack::PushL(TCleanupItem(CleanupServiceArray, implArray)); + } + CArrayFixFlat* datatypes = DataTypeArrayDeepCopyLC(infoRef.DataTypes()); + HBufC8* data = infoRef.OpaqueData().AllocLC(); + TApaAppServiceInfo info(app->AppEntry().iUidType[2], datatypes, data); + implArray->AppendL(info); + CleanupStack::Pop(data); + CleanupStack::Pop(datatypes); + } + } + } + } + app = NextApp(app, KIgnoreScreenMode); + } + + if (implArray) + { + CBufFlat* const buf = CBufFlat::NewL(KBufferExpansionGranularity); + CleanupStack::PushL(buf); + RBufWriteStream writeStream(*buf); + writeStream << *(implArray); + writeStream.CommitL(); + writeStream.Release(); + CleanupStack::Pop(buf); + CleanupStack::PopAndDestroy(implArray); + return buf; + } + + User::Leave(KErrNotFound); + return NULL; // to keep compiler happy + } + +CArrayFixFlat* CApaAppList::DataTypeArrayDeepCopyLC(const CArrayFixFlat& aOriginal) const + { + CArrayFixFlat* result = new(ELeave) CArrayFixFlat(1); + CleanupStack::PushL(result); + TInt ii = 0; + TInt end = aOriginal.Count(); + while (ii < end) + { + result->AppendL(aOriginal[ii]); + ii++; + } + + return result; + } + +EXPORT_C CApaAppList* CApaAppList::Self() + { // static + return STATIC_CAST(CApaAppList*,Dll::Tls()); + } + +/*EXPORT_C*/ RFs& CApaAppList::ShareProtectedFileServer() + { + return iFsShareProtected; //lint !e1536 Exposing low access member - need to consider a redesign or design clarification here(iFsShareProtected should be owned be the one that needs it) but postpone for now as that may require large changes + } + +CApaAppIconArray* CApaAppList::LoadDefaultIconsL() const + { + CApaIconLoader* iconLoader = CApaIconLoader::NewLC(iFs); + CApaAppIconArray* icons = CApaAppIconArray::NewRealDefaultIconsLC(KNumberOfIconsInDefaultMbm,*iDefaultAppIconMbmFileName, *iconLoader); + const TBool badMbmEntryInfo = !icons->LoadIconsL(); + if(badMbmEntryInfo) + { + CleanupStack::PopAndDestroy(2,iconLoader); + return CApaAppIconArray::NewL(); + } + else + { + CleanupStack::Pop(icons); + CleanupStack::PopAndDestroy(iconLoader); + } + + return icons; + } + +void CApaAppList::AcquireDefaultIconArrayL() const + { + ASSERT(iDefaultIconUsageCount >= 0); + if (iDefaultIconUsageCount == 0) + iDefaultIconArray = LoadDefaultIconsL(); + + ++iDefaultIconUsageCount; + } + +// Should NEVER be called by an object that does not call AcquireDefaultIconArrayL and +// ReleaseDefaultIconArray at the beginning and end of its lifetime respectively +const CApaAppIconArray& CApaAppList::DefaultIconArray() const + { + __ASSERT_ALWAYS(iDefaultIconArray, Panic(EPanicNullPointer)); + return *iDefaultIconArray; + } + +void CApaAppList::ReleaseDefaultIconArray() const + { + ASSERT(iDefaultIconUsageCount > 0); + if(0 == --iDefaultIconUsageCount) + { + delete iDefaultIconArray; + iDefaultIconArray = NULL; + } + } + +// DEF077478 - Required to update the default icons that the app list holds. +void CApaAppList::UpdateDefaultIconsL() + { + CApaAppIconArray* iconArray = LoadDefaultIconsL(); + if (iconArray) + { + delete iDefaultIconArray; + iDefaultIconArray = iconArray; + } + } + +void CApaAppList::DeleteAppListStorer() + { + delete iAppListStorer; + iAppListStorer = NULL; + } + +void CApaAppList::DeleteAppIconLoader() + { + delete iAppIconLoader; + iAppIconLoader = NULL; + } + +void CApaAppList::InitiateStoringOfAppList() + { + ScanComplete(); + NotifyObserver(); + iFlags &= ~ENotifyUpdateOnFirstScanComplete; + // now that the scan is finished, iDefaultAppIconMbmFileName is deleted + delete iDefaultAppIconMbmFileName; + iDefaultAppIconMbmFileName=NULL; + // if applist has not changed and AppsList_Backup.bin file exists then it is replaced back to AppsList.bin + if (!(iFlags & EAppListHasChanged) && BaflUtils::FileExists(iFs, iAppsListCacheBackUpFileName)) + { + TInt replaceError = iFs.Replace(iAppsListCacheBackUpFileName, iAppsListCacheFileName); + if (replaceError == KErrNone) + return; + } + + iFlags &= ~EAppListHasChanged; + iFs.Delete(iAppsListCacheBackUpFileName); + TInt err = iFs.MkDir(iAppsListCachePath); + if (err == KErrNone || err == KErrAlreadyExists) + { + TRAP(err, StoreL()); + if (err) + DeleteAppListStorer(); + } + } + + +EXPORT_C void CApaAppList::AddCustomAppInfoInListL(TUid aAppUid, TLanguage aLanguage, const TDesC& aShortCaption) + { + TBool replaced=EFalse; + for (TInt i=iCustomAppList.Count()-1; i>=0; --i) + { + if (aAppUid == iCustomAppList[i]->Uid() && aLanguage == iCustomAppList[i]->Language()) + { + CCustomAppInfoData* oldAppInfo = iCustomAppList[i]; + iCustomAppList[i] = CCustomAppInfoData::NewL(aAppUid, aLanguage, aShortCaption);; + delete oldAppInfo; + replaced=ETrue; + break; + } + } + //Add ELangNone items at the end and others at the beginning + if(!replaced) + { + CCustomAppInfoData* appInfo = CCustomAppInfoData::NewL(aAppUid, aLanguage, aShortCaption); + CleanupStack::PushL(appInfo); + + if(aLanguage == ELangNone) + iCustomAppList.AppendL(appInfo); + else + iCustomAppList.InsertL(appInfo,0); + + CleanupStack::Pop(appInfo); + } + + } //lint !e818 Suppress pointer parameter could be declared as pointing to const - this method takes ownership + + +EXPORT_C void CApaAppList::UpdateAppListByShortCaptionL() + { + //Items with ELangNone are always found at the end and other languages at the beginning + //While iterating from end to beginning, we overwrite short caption set by ELangNone if there is any provided for the application language + for (TInt i=iCustomAppList.Count()-1; i>=0; --i) + { + const CCustomAppInfoData* const customAppInfo=iCustomAppList[i]; + CApaAppData* app = AppDataByUid(customAppInfo->Uid()); + + if ( app && (app->ApplicationLanguage()==customAppInfo->Language() || customAppInfo->Language()==ELangNone)) + app->SetShortCaptionL(*customAppInfo->ShortCaption()); + } + } + +EXPORT_C void CApaAppList::UpdateAppListByIconCaptionOverridesL() + { + // get the language downgrade path, so that most appropriate language can be used + RArray languageDowngradePath; + CleanupClosePushL(languageDowngradePath); + BaflUtils::GetDowngradePathL(iFs, User::Language(), languageDowngradePath); + for (CApaAppData* app = FirstApp(); app; app = NextApp(app)) + { + CApaIconCaptionOverridesForApp* appOverride = iIconCaptionOverrides->OverrideForApp(app->AppEntry().iUidType[2]); + if (appOverride) + { + TApaIconCaptionOverrideReader overrideReader = appOverride->Reader(languageDowngradePath); + const TDesC* shortCaption = overrideReader.ShortCaption(); + if (shortCaption) + app->SetShortCaptionL(*shortCaption); + const TDesC* caption = overrideReader.Caption(); + if (caption) + app->SetCaptionL(*caption); + const TDesC* iconFileName = overrideReader.IconFileName(); + if (overrideReader.NumIconsSet() && iconFileName) + app->SetIconsL(*iconFileName, overrideReader.NumIcons()); + } + } + CleanupStack::PopAndDestroy(&languageDowngradePath); + } + +// +// Class CApaAppListStorer +// + +CApaAppList::CApaAppListStorer::CApaAppListStorer(CApaAppData* aFirstAppData, RFs& aFs, CApaAppList& aAppList) : CActive(EPriorityIdle), iCurrentAppData(aFirstAppData), iFs(aFs), iAppList(aAppList) + { + } + +CApaAppList::CApaAppListStorer::~CApaAppListStorer() + { + Cancel(); + iWriteStream.Close(); + iFs.Delete(iTempFilename); + iTimer.Close(); + iCurrentAppData = NULL; + } + +CApaAppList::CApaAppListStorer* CApaAppList::CApaAppListStorer::NewL(CApaAppData* aFirstAppData, RFs& aFs, CApaAppList& aAppList) + { + CApaAppListStorer* self = new(ELeave) CApaAppListStorer(aFirstAppData, aFs, aAppList); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CApaAppList::CApaAppListStorer::ConstructL() + { + User::LeaveIfError(iTimer.CreateLocal()); + CActiveScheduler::Add(this); + } + +void CApaAppList::CApaAppListStorer::StartL(const TTimeIntervalMicroSeconds32& aDelay) + { + User::LeaveIfError(iWriteStream.Temp(iFs, iAppList.iAppsListCachePath, iTempFilename, EFileWrite)); + iWriteStream.WriteInt32L(User::Language()); + +#if defined (SYMBIAN_BAFL_SYSUTIL) + //Write a cache of the ROM version to a separate stream + //Build the filename for the cache file + TInt maxSizeofFileName = iAppList.iAppsListCachePath.Length() + KROMVersionStringCacheFileName().Length(); + RBuf romVersionCacheFileName; + romVersionCacheFileName.CreateL(maxSizeofFileName); + romVersionCacheFileName.CleanupClosePushL(); + romVersionCacheFileName.Append(iAppList.iAppsListCachePath); + romVersionCacheFileName.Append(KROMVersionStringCacheFileName()); + + RFileWriteStream romVerStream; + User::LeaveIfError(romVerStream.Replace(iFs,romVersionCacheFileName,EFileWrite)); + CleanupClosePushL(romVerStream); + + // Write the file version that apparc can handle. + romVerStream.WriteInt8L(KROMVersionCacheFileMajorVersion); + romVerStream.WriteInt8L(KROMVersionCacheFileMinorVersion); + romVerStream.WriteInt16L(KROMVersionCacheFileBuildVersion); + + TBuf version; + SysUtil::GetSWVersion(version); + + // Write the software version even if SysUtil returns err since all conditions are taken care during restore. + romVerStream.WriteUint32L(version.Length()); + romVerStream.WriteL(version, version.Length()); + CleanupStack::PopAndDestroy(2); //romVerStream, romVersionCacheFileName +#endif //(SYMBIAN_BAFL_SYSUTIL) + + iTimer.After(iStatus, aDelay); + SetActive(); + } + +void CApaAppList::CApaAppListStorer::RunL() + { + // iStatus could be KErrNone or negative when timer completes, irrespective of its status we need to re-queue the request. + if (iCurrentAppData) + { + StoreEntryL(iWriteStream, *iCurrentAppData); + iCurrentAppData = iCurrentAppData->Next(); + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + else + { + iWriteStream.CommitL(); + iWriteStream.Close(); + + TInt err = iFs.Replace(iTempFilename, iAppList.iAppsListCacheFileName); + if (err != KErrNone) + iFs.Delete(iTempFilename); + + iAppList.DeleteAppListStorer(); + } + } + +void CApaAppList::CApaAppListStorer::StoreEntryL(RWriteStream& aWriteStream, const CApaAppData& aApp) + { + aWriteStream << aApp; + } + +void CApaAppList::CApaAppListStorer::DoCancel() + { + iTimer.Cancel(); + } + +TInt CApaAppList::CApaAppListStorer::RunError(TInt /*aError*/) + { + iAppList.DeleteAppListStorer(); + return KErrNone; + } + +// +// Class CApaIdleIconLoader +// + +CApaAppList::CApaIdleIconLoader::CApaIdleIconLoader(CApaAppData* aFirstAppData, RFs& aFs, CApaAppList& aAppList) : CActive(EPriorityLow), iCurrentAppData(aFirstAppData), iFs(aFs), iAppList(aAppList) + { // Priority is less than KAppListServerPriority, to maintain server responsiveness. + CActiveScheduler::Add(this); + } + +CApaAppList::CApaIdleIconLoader::~CApaIdleIconLoader() + { + Cancel(); + iCurrentAppData = NULL; + } + +void CApaAppList::CApaIdleIconLoader::Start() + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +void CApaAppList::CApaIdleIconLoader::RunL() +/** if the icons are not already loaded on demand then it would be loaded here. */ + { + while (iCurrentAppData && !iCurrentAppData->MbmIconsRequireLoading()) + iCurrentAppData = iCurrentAppData->Next(); + + if(iCurrentAppData) + { + Start(); + CApaAppData* const appData = iCurrentAppData; + iCurrentAppData = iCurrentAppData->Next(); + appData->LoadIconsL(); + } + else + { + iAppList.InitiateStoringOfAppList(); + iAppList.DeleteAppIconLoader(); + } + } + +void CApaAppList::CApaIdleIconLoader::DoCancel() + { + } + +TInt CApaAppList::CApaIdleIconLoader::RunError(TInt /*aError*/) + { + return KErrNone; + } + + +// +// Class CApaLangChangeMonitor +// + +CApaAppList::CApaLangChangeMonitor::~CApaLangChangeMonitor() + { + Cancel(); + iLangNotifier.Close(); + } + +CApaAppList::CApaLangChangeMonitor* CApaAppList::CApaLangChangeMonitor::NewL(CApaAppList& aAppList) + { // static + CApaLangChangeMonitor* self=new(ELeave) CApaLangChangeMonitor(aAppList); + self->ConstructL(); + return self; + } + +CApaAppList::CApaLangChangeMonitor::CApaLangChangeMonitor(CApaAppList& aAppList) + : CActive(EPriorityNormal), + iAppList(aAppList) + { + iPrevLanguage = User::Language(); + CActiveScheduler::Add(this); + } + +void CApaAppList::CApaLangChangeMonitor::ConstructL() + { + User::LeaveIfError(iLangNotifier.Create()); + Start(); + } + +void CApaAppList::CApaLangChangeMonitor::Start() + { + iLangNotifier.Logon(iStatus); + SetActive(); + } + +void CApaAppList::CApaLangChangeMonitor::DoCancel() + { + iLangNotifier.LogonCancel(); + } + +void CApaAppList::CApaLangChangeMonitor::RunL() + { + // Logon to get further events before handling current request. + TRequestStatus status = iStatus; + Start(); + + // if it is a language change event, start a rescan on app-list. + if (status.Int() == EChangesLocale && iPrevLanguage != User::Language()) + { + iPrevLanguage = User::Language(); + iAppList.iFlags |= CApaAppList::ELangChangePending; + iAppList.StartIdleUpdateL(iAppList.iObserver); + } + } + +TInt CApaAppList::CApaLangChangeMonitor::RunError(TInt /*aError*/) + { + // Reset ELangChangePending flag if RunL leaves. + iAppList.iFlags &= ~CApaAppList::ELangChangePending; + // Reset iPrevLanguage to ELangNone if RunL leaves. + iPrevLanguage = ELangNone; + return KErrNone; + } + +// +// CCustomAppInfoData +// + +CApaAppList::CCustomAppInfoData* CApaAppList::CCustomAppInfoData::NewL(TUid aAppUid, TLanguage aLanguage, const TDesC& aShortCaption) + { + CCustomAppInfoData* self=new(ELeave) CCustomAppInfoData(aAppUid, aLanguage); + CleanupStack::PushL(self); + self->ConstructL(aShortCaption); + CleanupStack::Pop(self); + return self; + } + +CApaAppList::CCustomAppInfoData::~CCustomAppInfoData() + { + delete iShortCaption; + } + +CApaAppList::CCustomAppInfoData::CCustomAppInfoData(TUid aAppUid, TLanguage aLanguage) + :iUid(aAppUid), + iLanguage(aLanguage) + { + } + +void CApaAppList::CCustomAppInfoData::ConstructL(const TDesC& aShortCaption) + { + iShortCaption=aShortCaption.AllocL(); + } + +TUid CApaAppList::CCustomAppInfoData::Uid() const + { return iUid; } + +TLanguage CApaAppList::CCustomAppInfoData::Language() const + { return iLanguage; } + +HBufC* CApaAppList::CCustomAppInfoData::ShortCaption() const + { return iShortCaption; } + +// The function transfers ownership of the pointer owned by a CApaAppList to the caller +// to avoid copying the array. + +EXPORT_C CArrayFixFlat* CApaAppList::UninstalledAppArray() + { + CArrayFixFlat* uninstalledApps=iUninstalledApps; + iUninstalledApps=NULL; + return uninstalledApps; + } +