smartinstaller/adm/src/ADMStateMachine.cpp
branchADM
changeset 48 364021cecc90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smartinstaller/adm/src/ADMStateMachine.cpp	Wed Jun 30 11:01:26 2010 +0530
@@ -0,0 +1,2340 @@
+/*
+* Copyright (c) 2009-2010 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: 
+*     State machine implementation
+*
+*
+*/
+
+
+#include <ADM.rsg>
+#include "ADMApplication.h" // KUidADMApp
+#include "ADMStateMachine.h"
+#include "ADMStateMachineDebug.h"
+#include "globals.h"
+#include "config.h"
+
+#include <e32std.h>
+#include <sysutil.h>        // SysUtil::DiskSpaceBelowCriticalLevel()
+#include <BAUTILS.H>
+#include <apgcli.h>
+
+// Use Char 0xFF to indicate no drive is selected
+const TChar KNoDriveSelected = 0xFF;
+
+// Used to force the progress bar to finish
+const TInt KProgressBarFullValue = 100;
+
+TInt CompareVersions(TVersion& version1, TVersion& version2);
+
+// ---------------------------------------------------------------------------
+// Panic
+//
+// Raises a panic with specific panic code.
+// ---------------------------------------------------------------------------
+//
+LOCAL_C inline void Panic(TInt aPanicCode)
+	{
+	_LIT(KPanic, "SmartInst-SM");
+	User::Panic( KPanic, aPanicCode );
+	}
+
+LOCAL_C inline void Panic(TInt aPanicCode, TInt aState)
+	{
+	_LIT(KPanic, "SmartInst-SM");
+	const TInt reason = aState*100 + aPanicCode;
+	User::Panic( KPanic, reason );
+	}
+
+// -----------------------------------------------------------------------------
+// Default constructor
+// -----------------------------------------------------------------------------
+//
+CStateMachine::CStateMachine(CADMAppUi& aAppUi) :
+	CActive(EPriorityNormal),
+	iAppUi(aAppUi),
+	iFailedState( CStateFactory::EStateLast )
+	{
+	CActiveScheduler::Add(this);
+	}
+
+// -----------------------------------------------------------------------------
+// NewL()
+// -----------------------------------------------------------------------------
+//
+CStateMachine* CStateMachine::NewL(CADMAppUi& aAppUi, const TDesC& aDownloadPath)
+	{
+	CStateMachine* self = new (ELeave) CStateMachine(aAppUi);
+	CleanupStack::PushL(self);
+	self->ConstructL(aDownloadPath);
+	CleanupStack::Pop();
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// ConstructL()
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::ConstructL(const TDesC& aDownloadPath)
+	{
+	// Create a local semaphore for handling the download deleting
+	// This must be the first to be created and last to be destroyed.
+	iDlDeletingSemaphore.CreateLocal(0);
+
+	iXmlParser = CXmlParser::NewL();
+	iSisParser = CSisParser::NewL();
+
+#ifdef USE_LOGFILE
+	iInstallManager = CInstallManager::NewL(this, iAppUi.iLog);
+	iDepTree = CDepTree::NewL(iAppUi.iLog, aDownloadPath);
+	iDownloadHandler = CDownloadHandler::NewL(this, iAppUi.iLog, !(iAppUi.EikonEnv()->StartedAsServerApp()));
+#else
+	iInstallManager = CInstallManager::NewL(this);
+	iDepTree = CDepTree::NewL(aDownloadPath);
+	iDownloadHandler = CDownloadHandler::NewL(this, !(iAppUi.EikonEnv()->StartedAsServerApp()));
+#endif
+
+	iStateFactory = CStateFactory::NewL(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CStateMachine::~CStateMachine()
+	{
+	if (IsActive())
+		{
+		Cancel();
+		}
+	delete iStateFactory;
+	delete iDownloadHandler;
+	delete iInstallManager;
+	delete iDepTree;
+	delete iSisParser;
+	delete iXmlParser;
+	delete iDownloadedFile;
+
+	iDlDeletingSemaphore.Close();
+	}
+
+// -----------------------------------------------------------------------------
+// Updates the displayed progress bar
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::UpdateProgressBar(TInt aStartValue, TInt aEndValue)
+	{
+	iAppUi.iProgress->Update(aStartValue, aEndValue);
+	}
+
+// -----------------------------------------------------------------------------
+// Removes the displayed progress bar
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::StopProgressBar() const
+	{
+	iAppUi.iProgress->Cancel();
+	}
+
+// -----------------------------------------------------------------------------
+// Sets the failure state and reason for exit
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::SetFailureReason(TExitReason aReason)
+	{
+	iAppUi.iExitReason = aReason;
+	iFailedState = (CStateFactory::TAppState)StateIndex();
+	// If the device is not supported, don't create resume info
+	if (aReason == EDeviceNotSupported)
+		{
+		iAppUi.iIsResumeRequired = EFalse;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// Shows the download query dialog with a specified text.
+// @param aResourceId Resource ID for the text to be shown.
+// @param aInfoResourceId Resource ID for additional information text.
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::ShowDownloadQueryL(const TInt aResourceId, const TInt aInfoResourceId)
+	{
+	iAppUi.ShowDownloadQueryL( aResourceId, aInfoResourceId );
+	}
+
+// -----------------------------------------------------------------------------
+// Shows wait note
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::ShowWaitNoteL(const TInt aResourceId)
+	{
+	iAppUi.ShowWaitNoteL( aResourceId, ETrue );
+	}
+
+// -----------------------------------------------------------------------------
+// Shows wait note with the specified values
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::ShowInstallingWaitNoteL(const TInt aCurrent, const TInt aLast)
+	{
+	iAppUi.ShowWaitNoteNumL( R_ADM_INSTALLING_TEXT, aCurrent, aLast );
+	}
+
+// -----------------------------------------------------------------------------
+// Shows the progress bar with the specified values
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::ShowProgressBarL(const TInt aStartValue, const TInt aEndValue, const TInt aCurrent, const TInt aLast)
+	{
+	iAppUi.ShowGlobalProgressL( R_ADM_DOWNLOADING_TEXT,
+			aStartValue, aEndValue,
+			aCurrent, aLast );
+	}
+
+// -----------------------------------------------------------------------------
+// Stops the wait note
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::StopWaitNote()
+	{
+	iAppUi.CancelWaitNote();
+	}
+
+// -----------------------------------------------------------------------------
+// Starts the state machine from the initial state.
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::Start()
+	{
+	LOG( "+ CStateMachine::Start()" );
+
+	// If the initial state has been set, don't change it here
+	if (!iState)
+		{
+		iState = &iStateFactory->GetState( CStateFactory::EStateSetup );
+		}
+
+	iStatus = KRequestPending;
+	SetActive();
+	// send signal that this request has completed
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+
+// -----------------------------------------------------------------------------
+// Stops the state machine
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::Stop()
+	{
+	LOG( "+ CStateMachine::Stop()" );
+	Cancel();
+	iDepTree->RemoveDownloadedFiles( FsSession() );
+	// Log statistics. Prevent divide-by-zero.
+	if (iDownloadTime == 0)
+		iDownloadTime = 1;
+	LOG4( "Total %d kB in %.1f s, avg %.2f kB/s",
+			iCumulativeDownloaded/1024,
+			iDownloadTime/1000000.0,
+			iCumulativeDownloaded*1000000.0 / iDownloadTime / 1024.0);
+	}
+
+// -----------------------------------------------------------------------------
+// Returns current state ID
+// -----------------------------------------------------------------------------
+//
+TInt CStateMachine::StateIndex() const
+	{
+	return iStateFactory->StateIndex(iState);
+	}
+
+// -----------------------------------------------------------------------------
+// Request the next state we want the application to go to
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::SetState(const CStateFactory::TAppState aState)
+	{
+	SetState( iStateFactory->GetState(aState) );
+	}
+
+// -----------------------------------------------------------------------------
+// Set the starting state of the state machine, but do not invoke state change
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::SetStartState(const CStateFactory::TAppState aState)
+	{
+	iState = &iStateFactory->GetState( aState );
+	}
+
+// -----------------------------------------------------------------------------
+// Request the next state we want the application to go to
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::SetState(TState& aState)
+	{
+	LOG3( "+ SetState(): %d -> %d", iStateFactory->StateIndex(iState), iStateFactory->StateIndex(&aState) );
+
+	iState->Exit();
+	iState = &aState;
+	SetActive();
+	// send signal that this request has completed
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+
+	//LOG2( "- SetState(): now in %d", iStateFactory->StateIndex(iState) );
+	}
+
+// -----------------------------------------------------------------------------
+// Active object heart
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::RunL()
+	{
+	//LOG2( "+ CStateEngine::RunL(): state=%d", iStateFactory->StateIndex(iState) );
+	iState->Enter();
+	//LOG2( "- CStateEngine::RunL(): %d", iStateFactory->StateIndex(iState) );
+	}
+
+// -----------------------------------------------------------------------------
+// Handles the leaves from RunL().
+//
+// SPECIFIC CASES NOT DONE YET:
+// -
+// -----------------------------------------------------------------------------
+//
+TInt CStateMachine::RunError(const TInt aError)
+	{
+	LOG3("+ SM::RunError(): %d, %d", StateIndex(), aError );
+
+	TExitReason err = EInstallationFailed;
+
+	switch ( aError )
+		{
+		case KLeaveExit:
+			{
+			// TODO: Ugly hack: we need to return KLeaveExit as RunError()
+			// gets called when application exit is called within RunL().
+			//LOG( "Exit() left" );
+			return KLeaveExit;
+			}
+		case SwiUI::KSWInstErrUserCancel:
+			{
+			LOG( "User cancelled installation" );
+			// User cancelled the installation
+			err = EUserCancelled;
+			}
+			break;
+		case SwiUI::KSWInstErrInsufficientMemory:
+			{
+			LOG( "Installer left: not enough space" );
+			err = EInsufficientMemory;
+			}
+			break;
+		case SwiUI::KSWInstErrMissingDependency:
+			{
+			LOG( "Installer left: missing dependency." );
+			//err = EInstallationFailed;
+			}
+			break;
+		case SwiUI::KSWInstErrFileCorrupted:
+		case SwiUI::KSWInstErrPackageNotSupported:
+		case SwiUI::KSWInstErrGeneralError:
+		case SwiUI::KSWInstErrNoRights:
+		case SwiUI::KSWInstErrNetworkFailure:
+		case SwiUI::KSWInstErrAccessDenied:
+		case SwiUI::KSWInstUpgradeError:
+			{
+			LOG2( "Installer left, err=%d", aError );
+			//err = EInstallationFailed;
+			}
+			break;
+		case KErrServerTerminated:
+			{
+			LOG( "Server process terminated, cannot continue." );
+			}
+			break;
+		case EUnsupportedDevice:
+			{
+			LOG( "MachineId not present in supported devices list" );
+			err = EDeviceNotSupported;
+			}
+			break;
+		case KErrAlreadyExists:
+			{
+			// Download already exists
+			LOG( "Existing download" );
+			err = EDownloadFailed;
+			}
+			break;
+		default:
+			{
+			LOG2( "Uncategorized leave %d, exiting", aError );
+			}
+			break;
+		}
+
+	LOG2( "Exiting due to failure %d", err );
+	SetFailureReason( err );
+	SetState( CStateFactory::EStatePrepareExitWithError );
+
+	return KErrNone;
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::DoCancel()
+	{
+	LOG( "CStateMachine::DoCancel()" );
+	iDownloadHandler->CancelAllDownloads();
+	iInstallManager->CancelAll();
+	}
+
+// -----------------------------------------------------------------------------
+// Sets the internet access point identifier for download handler
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::SetIAP(TUint32 aIAP)
+	{
+	iDownloadHandler->SetIAP(aIAP);
+	}
+
+// -----------------------------------------------------------------------------
+// Handles the UI event from AppUi, filters it and passes it to states.
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleUserResponse(TInt aStatus)
+	{
+	switch (aStatus)
+		{
+		case EAknSoftkeyYes:
+			iState->UserAccepted();
+			break;
+		case EAknSoftkeyNo:
+			iState->UserRejected();
+			break;
+		case EAknSoftkeyCancel:
+		case EKeyPhoneEnd:
+			// fall-through
+		default:
+			iState->UserCancelled();
+			break;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleInstallCompletedL(TInt aStatus)
+	{
+	LOG4( "HandleInstallCompletedL(%d): %d. '%S'", aStatus, StateIndex(), iCurrentPackage->GetSisPackageName() );
+	// TODO: Can iCurrentPackage ever be null? In case of root package installation??
+
+	iState->InstallCompleted( aStatus );
+	}
+
+// -----------------------------------------------------------------------------
+// Called, if IAP has changed
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleIapChanged(const TUint32 aIAP)
+	{
+	iAppUi.iIAP = aIAP;
+	SetIAP(aIAP);
+	}
+
+// -----------------------------------------------------------------------------
+// Called when download has finished.
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleHttpFetchCompleted(
+		const TDesC& aDlFilename,
+		const TInt /* aDownloadType */,
+		const TInt32 aBytesDownloaded,
+		const TReal32 aAvgDlSpeed, // bytes/second
+		const TInt64 aDlTime       // microseconds
+		)
+	{
+	delete iDownloadedFile;
+	iDownloadedFile = NULL;
+	iDownloadedFile = aDlFilename.Alloc();
+	iDownloadSize = aBytesDownloaded;
+	// Indicate that we've downloaded this amount already to keep progress bar happy
+	iCumulativeDownloaded += aBytesDownloaded;
+	// Calculate cumulative average download speed
+	iDownloadTime += aDlTime;
+
+#ifdef DEBUG_ADM
+	TReal32 avgDlSpeed = iCumulativeDownloaded*1000000.0 / iDownloadTime;
+
+#ifdef _DEBUG
+	TBuf<32> buf;
+	TReal r = avgDlSpeed;
+	TRealFormat fmt(3, 2);
+	fmt.iType = KRealFormatFixed; // | KDoNotUseTriads;
+	buf.AppendNum(r/1024.0, fmt);
+	buf.Append(' ');
+	buf.Append(iAppUi.iPrefixKb);
+	buf.Append('/');
+	buf.Append('s');
+	iAppUi.EikonEnv()->InfoMsg(buf);
+#endif
+
+	LOG8( "DL %7d/%7d (%.1f s, %3.02f kB/s) (total: %d kB, %.1f s, avg %.02f kB/s) OK",
+			aBytesDownloaded, aBytesDownloaded, aDlTime/1000000.0, aAvgDlSpeed/1024.0,
+			iCumulativeDownloaded/1024, iDownloadTime/1000000.0, avgDlSpeed/1024.0 );
+#endif
+	iState->DownloadCompleted(aBytesDownloaded);
+	}
+
+// -----------------------------------------------------------------------------
+// Called when download manager has retrieved a packet from the network.
+// Required for updating the progress bar.
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleHttpFetchInProgress(const TInt32 aAlreadyDownloaded, const TInt32 aDownloadSize, const TReal32 aAvgDlSpeed)
+	{
+	iState->DownloadInProgress(aAlreadyDownloaded, aDownloadSize, aAvgDlSpeed);
+	}
+
+// -----------------------------------------------------------------------------
+// Called when download manager encounters a problem while downloading
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleHttpFetchFailure(
+		const TDesC& aDlFilename,
+		const TInt aGlobalErrorId,
+		const TInt aErrorId,
+		const TInt aFetchType
+		)
+	{
+	if (aFetchType)
+		{
+		LOG5( "+ HandleHttpFetchFailure(): %d. %d, %d '%S'", StateIndex(), aGlobalErrorId, aErrorId, &aDlFilename );
+		}
+	delete iDownloadedFile;
+	iDownloadedFile = NULL;
+	iDownloadedFile = aDlFilename.Alloc();
+	// TODO: Filter the errors here and invoke proper callbacks in states
+	iState->DownloadFailed();
+	LOG( "- HandleHttpFetchFailure()" );
+	}
+
+// -----------------------------------------------------------------------------
+// Signals the semaphore that download deleting is in progress (and the installation
+// can safely continue).
+// -----------------------------------------------------------------------------
+//
+void CStateMachine::HandleDownloadDeleting()
+	{
+	iDlDeletingSemaphore.Signal();
+	}
+
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TState& CStateFactory::GetState(const TAppState aState) const
+	{
+	__ASSERT_DEBUG( aState < EStateLast, Panic(EPanicStateIndexOutOfBounds) );
+	return *iStates[aState];
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TInt CStateFactory::StateIndex(const TState* aState) const
+	{
+	TInt state;
+	for (state = 0; state < EStateLast; state++)
+		{
+		if (iStates[state] == aState)
+			{
+			return state;
+			}
+		}
+	// We end up here, if the state is not set, which may happen, if this
+	// is called before CStateMachine::Start() or CStateMachine::SetState().
+	return KUnknownState;
+	}
+
+// -----------------------------------------------------------------------------
+// Creates a new CStateFactory.
+// @return Newly created CStateFactory.
+// -----------------------------------------------------------------------------
+//
+CStateFactory* CStateFactory::NewL(CStateMachine& aStateMachine)
+	{
+	CStateFactory* self = new (ELeave) CStateFactory(aStateMachine);
+	CleanupStack::PushL(self);
+
+	// Create the states
+	self->iStates[EStateSetup]                      = new (ELeave) TStateSetup(*self);
+	self->iStates[EStateSetupParsing]               = new (ELeave) TStateSetupParsing(*self);
+	self->iStates[EStateBuildDepTree]               = new (ELeave) TStateBuildDepTree(*self);
+	self->iStates[EStateDownloadDepFile]            = new (ELeave) TStateDownloadDepFile(*self);
+	self->iStates[EStateParseDepFile]               = new (ELeave) TStateParseDepFile(*self);
+	self->iStates[EStateDownloadChangesFile]        = new (ELeave) TStateDownloadChangesFile(*self);
+	self->iStates[EStateParseChangesFile]           = new (ELeave) TStateParseChangesFile(*self);
+	self->iStates[EStateBuildFetchList]             = new (ELeave) TStateBuildFetchList(*self);
+	self->iStates[EStateVerifyAvailableDiskSpace]   = new (ELeave) TStateVerifyAvailableDiskSpace(*self);
+	self->iStates[EStateConfirmDownload]            = new (ELeave) TStateConfirmDownload(*self);
+	self->iStates[EStateConfirmRoamingDownload]     = new (ELeave) TStateConfirmRoamingDownload(*self);
+	self->iStates[EStateStartDependencyDownload]    = new (ELeave) TStateStartDependencyDownload(*self);
+	self->iStates[EStateDownloadDependency]         = new (ELeave) TStateDownloadDependency(*self);
+	self->iStates[EStateInstallDependency]          = new (ELeave) TStateInstallDependency(*self);
+	self->iStates[EStateInstallAppSis]              = new (ELeave) TStateInstallAppSis(*self);
+	self->iStates[EStateUninstallDependency]        = new (ELeave) TStateUninstallDependency(*self);
+	self->iStates[EStatePrepareExitWithError]       = new (ELeave) TStatePrepareExitWithError(*self);
+	self->iStates[EStateLaunchApp]                  = new (ELeave) TStateLaunchApp(*self);
+	self->iStates[EStateExit]                       = new (ELeave) TStateExit(*self);
+
+	CleanupStack::Pop();
+
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// Default constructor
+// -----------------------------------------------------------------------------
+//
+CStateFactory::CStateFactory(CStateMachine& aStateMachine) :
+	iStateMachine(aStateMachine)
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// Default destructor
+// -----------------------------------------------------------------------------
+//
+CStateFactory::~CStateFactory()
+	{
+	// Deletes all state objects
+	iStates.DeleteAll();
+	}
+
+// =============================================================================
+
+TState::TState(const CStateFactory& aFactory) :
+	iFactory(aFactory),
+	iStateMachine(aFactory.StateMachine())
+	{
+	}
+
+void TState::PanicInState(TStatePanic aPanic) const
+	{
+	Panic(aPanic, iFactory.StateIndex(this));
+	}
+
+// Change of states
+void TState::Enter() const
+	{
+	}
+
+void TState::Exit() const
+	{
+	}
+
+// Events from UI
+void TState::UserAccepted()
+	{
+	LOG_FUNC
+	}
+
+// -----------------------------------------------------------------------------
+// Implements the default user cancel behaviour. If needed, overwrite in the
+// state implementation.
+// -----------------------------------------------------------------------------
+//
+void TState::UserCancelled()
+	{
+	LOG_FUNC
+	iStateMachine.SetFailureReason(EUserCancelled);
+	iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+	}
+
+// -----------------------------------------------------------------------------
+// Implements the default user reject behaviour. If needed, overwrite in the
+// state implementation.
+// -----------------------------------------------------------------------------
+//
+void TState::UserRejected()
+	{
+	UserCancelled();
+	}
+
+// Events from DownloadManager
+void TState::DownloadInProgress(const TInt /* aAlreadyDownloaded */, const TInt /* aDownloadSize */, const TReal32 /* aAvgDlSpeed */)
+	{
+	//LOG_FUNC
+	}
+
+void TState::DownloadCompleted(const TInt /* aBytesDownloaded */)
+	{
+	LOG_FUNC
+	}
+
+ void TState::DownloadFailed()
+	{
+	LOG_FUNC
+	}
+
+void TState::DownloadFailed(const CStateFactory::TAppState aState)
+	{
+	const EDownloadError errId = iStateMachine.iDownloadHandler->GetDownloadError();
+	SLOG3( "+ DownloadFailed(): %d. err=%d", iStateMachine.StateIndex(), errId );
+
+	if ( (errId == EDlErrDownloadFailure ) && ( iStateMachine.iRestartAttempt < KDownloadRestartRetries) )
+		{
+		iStateMachine.iRestartAttempt++;
+		SLOG2( "Download restart, attempt %d", iStateMachine.iRestartAttempt );
+		iStateMachine.SetState( aState );
+		}
+	else
+		{
+		SLOG3( "Aborting download. (%d; %d)", iStateMachine.iRestartAttempt, errId );
+//      iStateMachine.iRestartAttempt = 0;
+		iStateMachine.SetFailureReason(EDownloadFailed);
+		iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+		}
+	}
+
+void TState::DownloadCancelled()
+	{
+	LOG_FUNC
+	iStateMachine.SetFailureReason(EUserCancelled);
+	iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+	}
+
+// Events from InstallManager
+void TState::InstallInProgress()
+	{
+	LOG_FUNC
+	}
+
+void TState::InstallCompleted(TInt /* aStatus */)
+	{
+	LOG_FUNC
+	}
+
+void TState::InstallationCancelled()
+	{
+	LOG_FUNC
+	}
+
+// =============================================================================
+TStateSetup::TStateSetup(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	LOG_FUNC
+	}
+
+void TStateSetup::Enter() const
+	{
+	LOG_FUNC
+
+	// TODO: Check if we are roaming and proceed according to that
+
+	iStateMachine.SetState( CStateFactory::EStateSetupParsing );
+	}
+
+TStateSetupParsing::TStateSetupParsing(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateSetupParsing::Enter() const
+	{
+	const TInt mUid = iStateMachine.MachineUid();
+	if ( mUid )
+		{
+		iStateMachine.iDepTree->SetMachineId( mUid );
+		}
+	else
+		{
+		PanicInState( EPanicStateInvalidMachineUid );
+		}
+
+	// Get the drive where wrapper package was installed to
+	const TBool driveStatus = iStateMachine.iInstallManager->GetPackageInstalledDriveL(
+			iStateMachine.WrapperPackageUid(),
+			iStateMachine.iWrapperInstalledDrive);
+
+
+#ifdef __WINS__
+	iStateMachine.iWrapperInstalledDrive = 'C';
+#else
+	if ( !driveStatus )
+		{
+		// Read the wrapper installed drive from resume info file.
+		// TODO: What if user has tried to install on a removable drive and it's not available during the menu launch?
+		}
+#endif
+
+	SLOG3( "Installer pkg on %c: (%d)", (char)iStateMachine.iWrapperInstalledDrive, driveStatus );
+
+	// Cannot combine this with drive status. User might be trying to reinstall an app, already present in the device!
+	TVersion version, minVersion = KMinBootstrapSisVersion;
+	if ( iStateMachine.iInstallManager->GetPackageVersionInfoL(KUidBootstrap, version) )
+		{
+		// Compare installed and min required Bootstrap versions
+		if ( CompareVersions(minVersion, version) == EGreaterFirstVersion )
+			{
+			iStateMachine.SetFailureReason( EInvalidBootstrapVersion );
+			iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+			return;
+			}
+		}
+	else
+		{
+		// Launched from the menu grid
+		}
+
+	switch ( iStateMachine.BootstrapVersion() )
+		{
+		case 1:
+		case 2:
+		case 3:
+			{
+			// Parses the dependency file included withing the wrapper package.
+			SLOG2( "* Parsing '%S'", iStateMachine.DepFilename() );
+			iStateMachine.iXmlParser->GetDepContentsL(
+					*iStateMachine.DepFilename(),
+					iStateMachine.iCurrentPackage,
+					iStateMachine.iDepTree
+				);
+			iStateMachine.SetState( CStateFactory::EStateBuildDepTree );
+			}
+			break;
+		case 4:
+			{
+			// Parses the application.sis file included in the wrapper package.
+			SLOG2( "* Parsing '%S'", iStateMachine.SisFilename() );
+			iStateMachine.iSisParser->GetDepContentsL(
+					*iStateMachine.SisFilename(),
+					iStateMachine.iCurrentPackage,
+					iStateMachine.iDepTree
+				);
+			iStateMachine.SetState( CStateFactory::EStateBuildDepTree );
+			}
+			break;
+		default:
+			{
+			SLOG2( "Invalid bootstrap v%d", iStateMachine.BootstrapVersion() );
+			iStateMachine.SetFailureReason( EInvalidBootstrapVersion );
+			iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+			}
+			break;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateParseDepFile::TStateParseDepFile(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateParseDepFile::Enter() const
+	{
+	SLOG2( "+ ParseDepFileL(): '%S'", iStateMachine.iDownloadedFile );
+	iStateMachine.iXmlParser->GetDepContentsL(
+			*iStateMachine.iDownloadedFile,
+			iStateMachine.iCurrentPackage,
+			iStateMachine.iDepTree
+		);
+	iStateMachine.SetState( CStateFactory::EStateBuildDepTree );
+	SLOG2( "- ParseDepFileL(): '%S'", iStateMachine.iDownloadedFile );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateParseChangesFile::TStateParseChangesFile(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateParseChangesFile::Enter() const
+	{
+	SLOG2("+ ParseChangesFileL(): '%S'", iStateMachine.iDownloadedFile);
+	// Parse the provided changes file.
+	// the parameter aChangesFileName will be invalid after the call
+	iStateMachine.iXmlParser->GetChangesInfoL(
+			*iStateMachine.iDownloadedFile,
+			iStateMachine.iCurrentPackage,
+			iStateMachine.iDepTree
+		);
+	iStateMachine.SetState( CStateFactory::EStateDownloadDepFile );
+	SLOG2( "- ParseChangesFileL(): '%S'", iStateMachine.iDownloadedFile );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateBuildFetchList::TStateBuildFetchList(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateBuildFetchList::Enter() const
+	{
+	// Construct the list of dependent packages
+	SLOG( "Building dependency list" );
+	iStateMachine.iDepTree->ConstructFetchListL();
+
+	// Remove all downloaded dep files
+	SLOG( "Removing downloaded files" );
+	iStateMachine.iDepTree->RemoveDownloadedFiles( iStateMachine.FsSession() );
+
+	// Check if cycle exists
+	if ( iStateMachine.iDepTree->IsCyclePresent() )
+		{
+		// TODO: Inform user about configuration failure, exit gracefully
+		SLOG( "! Failure: cycle exists in the graph." );
+		iStateMachine.SetFailureReason( EInstallationFailed );
+		iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+		}
+	iStateMachine.SetState( CStateFactory::EStateVerifyAvailableDiskSpace );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateVerifyAvailableDiskSpace::TStateVerifyAvailableDiskSpace(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateVerifyAvailableDiskSpace::Enter() const
+	{
+	// MaxDownloadSize is subtracted from available System drive space.
+
+	// In case of silent installation of main app, if there is no space available in the drive selected by the user for wrapper,
+	// normal installation to follow.
+
+	// Set the drive info
+	if ( iStateMachine.iDepTree->SetDriveInfo() )
+		{
+		// With Ovi Store prompt always
+		const TInt dlThreshold = iStateMachine.OviStoreRunning()
+				? 0
+				: KDownloadPromptThreshold;
+		const TInt dlSize = iStateMachine.iDepTree->GetTotalDownloadSize();
+
+		SLOG3( "Download size %d (%d)", dlSize, dlThreshold );
+
+#ifdef DEBUG_ADM
+		// Print all the drives set. To be removed after testing.
+		CPackageInfo *node = NULL;
+		while( (node = iStateMachine.iDepTree->GetNextSortedNode()) != NULL )
+			{
+			SLOG5( "PkgUid 0x%08X: InstDrive %c:, prio %d, size %d",
+					node->GetPackageUid(), (char)node->GetInstallDrive(),
+					node->GetDrivePriority(), node->GetInstallSize() );
+			}
+#endif
+		// Show user how much to download and confirm, if he/she wants to do that
+		// if we have dependencies to download at all
+		if ( dlSize > 0 )
+			{
+			// Finalize the progress bar
+			iStateMachine.UpdateProgressBar( KProgressBarFullValue, KProgressBarFullValue );
+
+			// We need to download dependencies
+			if ( iStateMachine.UsingWLAN() && !iStateMachine.OviStoreRunning() )
+				{
+				// If using WLAN, start the dependency download immediately without prompting the user
+				iStateMachine.SetState( CStateFactory::EStateStartDependencyDownload );
+				}
+			else if ( iStateMachine.RegisteredRoaming() )
+				{
+				// If the device is roaming, always prompt the user
+				iStateMachine.SetState( CStateFactory::EStateConfirmRoamingDownload );
+				}
+			else if ( dlSize > dlThreshold )
+				{
+				// If not using WLAN and the download threshold has exceeded, prompt the user
+				iStateMachine.SetState( CStateFactory::EStateConfirmDownload );
+				}
+			else
+				{
+				// Otherwise, continue the download automatically without prompting the user
+				iStateMachine.SetState( CStateFactory::EStateStartDependencyDownload );
+				}
+			}
+		else
+			{
+			SLOG( "Nothing to download, dependencies OK." );
+			// Keep the next progress bar update happy
+			iStateMachine.iProgressMaxValue = KProgressBarFullValue;
+			// Finalize the progress bar
+			iStateMachine.UpdateProgressBar( KProgressBarFullValue*95/100, KProgressBarFullValue );
+			iStateMachine.SetState( CStateFactory::EStateInstallAppSis );
+			}
+		}
+	else
+		{
+		iStateMachine.SetFailureReason( EInsufficientMemory );
+		iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// Builds the dependency tree. This function controls the state machine.
+// -----------------------------------------------------------------------------
+//
+TStateBuildDepTree::TStateBuildDepTree(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateBuildDepTree::Enter() const
+	{
+	SLOG2( "+ BuildDepTreeL(%d)", iStateMachine.iNodesProcessed );
+
+	// Update progress bar
+	iStateMachine.iNodesProcessed++;
+
+	iStateMachine.iCurrentPackage = iStateMachine.iDepTree->GetNextNode();
+	CPackageInfo* package = iStateMachine.iCurrentPackage;
+
+	if ( package == NULL )
+		{
+		SLOG( "Last package processed" );
+		// Do the final progress bar update
+		iStateMachine.UpdateProgressBar( KProgressBarFullValue*95/100, KProgressBarFullValue );
+
+		iStateMachine.SetState( CStateFactory::EStateBuildFetchList );
+		}
+	else
+		{
+		SLOG3( "* Processing 0x%08X (%d)", package->GetPackageUid(), package->GetPackageStatus() );
+
+		iStateMachine.UpdateProgressBar( iStateMachine.iNodesProcessed,
+				iStateMachine.iNodesProcessed+2 );
+
+		// Call the install class api to validate and set the package status
+		TUid uid = TUid::Uid( package->GetPackageUid() );
+		TVersion version, test;
+
+		test = package->GetPackageVersion();
+
+		if (iStateMachine.iInstallManager->GetPackageVersionInfoL(uid, version))
+			{
+			// Compare installed and required verions
+			// to find if upgrade is required.
+			if ( (CompareVersions(test, version) ) == EGreaterFirstVersion)
+				{
+				SLOG8( "Package 0x%08X: upgrade %d.%02d.%d -> %d.%02d.%d",
+						uid.iUid,
+						version.iMajor, version.iMinor, version.iBuild,
+						test.iMajor, test.iMinor, test.iBuild
+						);
+				package->SetPackageStatus(EPackageToBeUpgraded);
+				}
+			else
+				{
+				SLOG5( "Package 0x%08X: v%d.%02d.%d already installed", uid.iUid,
+						version.iMajor, version.iMinor, version.iBuild
+						);
+				package->SetPackageStatus(EPackageInstalled);
+				}
+			}
+		else
+			{
+			SLOG5( "Package 0x%08X: v%d.%02d.%d to be downloaded", uid.iUid,
+					test.iMajor, test.iMinor, test.iBuild
+					);
+			package->SetPackageStatus(EPackageToBeFetched);
+			}
+
+		iStateMachine.SetState( CStateFactory::EStateDownloadChangesFile );
+		}
+	SLOG2( "- BuildDepTreeL(%d)", iStateMachine.iNodesProcessed );
+	}
+
+// -----------------------------------------------------------------------------
+// Requests a download for the dependecy sis package _dep.xml file.
+// -----------------------------------------------------------------------------
+//
+TStateDownloadDepFile::TStateDownloadDepFile(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateDownloadDepFile::Enter() const
+	{
+	//Here fetch the dep file of the current package.
+	SLOG2( "+ FetchDepFileL(): 0x%08X", iStateMachine.iCurrentPackage->GetPackageUid() );
+
+	// TODO:Here the download Url should never be null]
+	// as its mandatory to specify the Url in changes file.
+	TPtrC8 urlPtr(NULL, 0);
+	if (iStateMachine.iCurrentPackage->GetDownloadUrlL() != NULL)
+		{
+		SLOG8_2( "DepPkg URL: '%S'", iStateMachine.iCurrentPackage->GetDownloadUrlL() );
+		urlPtr.Set(iStateMachine.iCurrentPackage->GetDownloadUrlL()->Des() );
+		}
+	else
+		{
+		SLOG8_2( "DepPkg URL: '%S' (default)", iStateMachine.ConfigUrl() );
+		urlPtr.Set( *iStateMachine.ConfigUrl() );
+		}
+
+	User::LeaveIfNull( iStateMachine.iCurrentPackage->GetDepFileName() );
+
+	SLOG2( "Downloading DEP: '%S'", iStateMachine.iCurrentPackage->GetDepFileName() );
+
+	iStateMachine.iDownloadHandler->StartDownloadL(
+		urlPtr,
+		*iStateMachine.iCurrentPackage->GetDepFileName(),
+		iStateMachine.iDepTree->GetDownloadPath(),
+		1);
+	// We don't request a new state after this. When download completes
+	// succesfully, a new state change will be requested.
+	}
+
+void TStateDownloadDepFile::DownloadCompleted(const TInt /* aBytesDownloaded */)
+	{
+	iStateMachine.iRestartAttempt = 0;
+	iStateMachine.SetState( CStateFactory::EStateParseDepFile );
+	}
+
+void TStateDownloadDepFile::DownloadFailed()
+	{
+	LOG_FUNC
+	TState::DownloadFailed( CStateFactory::EStateDownloadDepFile );
+	}
+
+// -----------------------------------------------------------------------------
+// Requests a download for the _changes.xml file.
+// -----------------------------------------------------------------------------
+//
+TStateDownloadChangesFile::TStateDownloadChangesFile(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateDownloadChangesFile::Enter() const
+	{
+	// See if the URL is provided as part of the
+	// dep file, otherwise use the default one.
+	TPtrC8 urlPtr(NULL, 0);
+	if ( iStateMachine.iCurrentPackage->GetURL() != NULL )
+		{
+		SLOG8_2( "Changes URL: '%S'", iStateMachine.iCurrentPackage->GetURL() );
+		urlPtr.Set(iStateMachine.iCurrentPackage->GetURL()->Des());
+		}
+	else
+		{
+		SLOG8_2( "Changes URL: '%S' (default)", iStateMachine.ConfigUrl() );
+		urlPtr.Set( *iStateMachine.ConfigUrl() );
+		}
+
+		//TODO: The only reason why this is back here :
+		//Changes file name for Root is not set when root is parsed. Fix it.
+		iStateMachine.iCurrentPackage->SetChangesFileNameL();
+	SLOG2( "Downloading CHANGES: '%S'", iStateMachine.iCurrentPackage->GetChangesFileName() );
+
+	// Download the changes file
+	iStateMachine.iDownloadHandler->StartDownloadL(
+		urlPtr,
+		*iStateMachine.iCurrentPackage->GetChangesFileName(),
+		iStateMachine.iDepTree->GetDownloadPath(),
+		0);
+	// We don't request a new state after this. When download completes
+	// succesfully, a new state change will be requested by DownloadCompleted()
+	}
+
+void TStateDownloadChangesFile::DownloadCompleted(const TInt /*aBytesDownloaded*/)
+	{
+	LOG_FUNC
+
+	iStateMachine.iNodesProcessed++;
+	iStateMachine.UpdateProgressBar( iStateMachine.iNodesProcessed, iStateMachine.iNodesProcessed+2 );
+
+	iStateMachine.iRestartAttempt = 0;
+	iStateMachine.SetState( CStateFactory::EStateParseChangesFile );
+	}
+
+void TStateDownloadChangesFile::DownloadFailed()
+	{
+	LOG_FUNC
+	TState::DownloadFailed( CStateFactory::EStateDownloadChangesFile );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateStartDependencyDownload::TStateStartDependencyDownload(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateStartDependencyDownload::Enter() const
+	{
+	const TUint32 totalDlSize = iStateMachine.iDepTree->GetTotalDownloadSize();
+	SLOG2( "Starting to download %d bytes", totalDlSize );
+
+	// Remove all downloads before proceeding
+	iStateMachine.iDownloadHandler->CancelAllDownloads();
+
+	// Start progress bar from beginning
+	iStateMachine.iCounterCurrent = 1;
+	iStateMachine.iCounterMax = iStateMachine.iDepTree->CountDownloadNodes();
+
+	// reset to zero for download and install of packages.
+	iStateMachine.iDownloadSize = 0;
+	iStateMachine.iNodesProcessed = 0;
+
+	// Start the dependency download!
+	iStateMachine.SetState( CStateFactory::EStateDownloadDependency );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateDownloadDependency::TStateDownloadDependency(const CStateFactory& aFactory) :
+	TState(aFactory),
+	iRetryDownload(EFalse)
+	{
+	}
+
+void TStateDownloadDependency::Enter() const
+	{
+	SLOG3( "+ FetchPackageL(%d): retry=%d", iStateMachine.iNodesProcessed, iRetryDownload );
+
+	CPackageInfo* fetchPackage = NULL;
+
+	if ( iRetryDownload )
+		{
+		fetchPackage = iStateMachine.iDepTree->GetCurrentFetchNode();
+		}
+	else
+		{
+		iStateMachine.iNodesProcessed++;
+		// always ensure that iCurrentPackage points to the correct one
+		fetchPackage = iStateMachine.iDepTree->GetNextFetchNode();
+		}
+	iStateMachine.iCurrentPackage = fetchPackage;
+
+	if ( !fetchPackage )
+		{
+/*
+		//end of list - we're finished
+		SLOG2( "Uninstalling wrapper 0x%08X", iStateMachine.WrapperPackageUid().iUid );
+		TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage(
+			iStateMachine.WrapperPackageUid() );
+		SLOG2( "Uninstall status: %d", err);
+*/
+		// Wrapper has been uninstalled, ready to exit/launch
+		iStateMachine.SetState( CStateFactory::EStateExit );
+		return;
+		}
+/*
+	// Attempting to fix 'Network connection lost!' errors on 3G. Does not help.
+	SLOG( "Deleting all downloads" );
+	iStateMachine.iDownloadHandler->CancelAllDownloads();
+*/
+	switch ( fetchPackage->GetPackageStatus() )
+		{
+		case EPackageRootToBeInstalled:
+			{
+			//SLOG( "* Installing AppSis" );
+
+			iStateMachine.SetState( CStateFactory::EStateInstallAppSis );
+			}
+			break;
+		case EPackageToBeFetched:
+		case EPackageToBeUpgraded:
+			{
+			SLOG2( "* Package 0x%08X to be Fetched/Upgraded", fetchPackage->GetPackageUid() );
+
+			// Initialize progress bar
+			//ShowGlobalProgressL(R_ADM_DOWNLOAD_WAIT_TEXT, 0, KMaxTInt);
+
+			if ( iStateMachine.iCounterMax > 0 )
+				{
+				iStateMachine.StopWaitNote();
+				// prevent progress bar from starting from previous dl size
+				iStateMachine.iProgressCurrentValue = 0;
+				iStateMachine.iCumulativeDepDownloaded = 0;
+				iStateMachine.iProgressMaxValue = fetchPackage->GetDownloadSize();
+				iStateMachine.ShowProgressBarL(
+						0,
+						iStateMachine.iProgressMaxValue,
+						iStateMachine.iCounterCurrent,
+						iStateMachine.iCounterMax
+						);
+				}
+
+			// TODO:Here the download Url should never be null,
+			// as its mandatory to specify the Url in changes file.
+			TPtrC8 urlPtr(NULL, 0);
+			if (fetchPackage->GetDownloadUrlL() != NULL )
+				{
+				SLOG8_2( "Package URL: '%S'", fetchPackage->GetDownloadUrlL());
+				urlPtr.Set(fetchPackage->GetDownloadUrlL()->Des());
+				}
+			else
+				{
+				SLOG8_2( "Package URL: '%S' (default)", iStateMachine.ConfigUrl() );
+				urlPtr.Set(*iStateMachine.ConfigUrl());
+				}
+
+			User::LeaveIfNull( fetchPackage->GetSisPackageName() );
+
+			SLOG2( "Downloading: '%S'", fetchPackage->GetSisPackageName() );
+			iStateMachine.iDownloadHandler->StartDownloadL(
+				urlPtr,
+				*fetchPackage->GetSisPackageName(),
+				iStateMachine.iDepTree->GetDownloadPath(),
+				2);
+			}
+			break;
+		case EPackageInstalled:
+			{
+			SLOG2( "* Package 0x%08X installed", fetchPackage->GetPackageUid());
+			//FetchPackageL();
+			iStateMachine.SetState( CStateFactory::EStateDownloadDependency );
+			}
+			break;
+		default:
+			{
+			// TODO: Better error handling
+			Panic( EPanicStateFetchStatus );
+			}
+			break;
+		} // switch
+	SLOG2( "- FetchPackageL(%d)", iStateMachine.iNodesProcessed );
+	}
+
+void TStateDownloadDependency::DownloadCompleted(const TInt aBytesDownloaded)
+	{
+	iRetryDownload = EFalse;
+	// Indicate that we've downloaded this amount already to keep progress bar happy
+	iStateMachine.iCumulativeDepDownloaded += aBytesDownloaded;
+	iStateMachine.iDownloadSize = iStateMachine.iCumulativeDepDownloaded;
+	iStateMachine.SetState( CStateFactory::EStateInstallDependency );
+	}
+
+void TStateDownloadDependency::DownloadInProgress(const TInt aAlreadyDownloaded, const TInt aDownloadSize, const TReal32 aAvgDlSpeed)
+	{
+	static TInt32 prevAlready = 0;
+	// Prevents log and event flooding
+	if (aAlreadyDownloaded != prevAlready)
+		{
+		prevAlready = aAlreadyDownloaded;
+
+		iStateMachine.iDownloadSize = aAlreadyDownloaded + iStateMachine.iCumulativeDepDownloaded;
+		iStateMachine.iProgressCurrentValue =
+				iStateMachine.iCumulativeDepDownloaded + aAlreadyDownloaded;
+		if (aAvgDlSpeed > 0)
+			{
+			SLOG4( "DL %7d/%7d (%3.02f kB/s)", aAlreadyDownloaded, aDownloadSize, aAvgDlSpeed/1024 );
+			}
+		else
+			{
+			SLOG3( "DL %7d/%7d", aAlreadyDownloaded, aDownloadSize );
+			}
+		// Update the progress bar
+		iStateMachine.UpdateProgressBar( iStateMachine.iProgressCurrentValue,
+				iStateMachine.iProgressMaxValue );
+		}
+	}
+
+void TStateDownloadDependency::DownloadFailed()
+	{
+	LOG_FUNC
+	iRetryDownload = ETrue;
+	TState::DownloadFailed( CStateFactory::EStateDownloadDependency );
+	}
+
+// -----------------------------------------------------------------------------
+// Uninstalls installed dependencies one at the time
+// -----------------------------------------------------------------------------
+//
+TStateUninstallDependency::TStateUninstallDependency(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateUninstallDependency::Enter() const
+	{
+	CPackageInfo* node = iStateMachine.iDepTree->GetPreviousFetchNode();
+	// Uninstall all the fetched and installed dependencies
+	if (node)
+		{
+		// TODO: Can the package present check be moved to Install handler?. Below is an async function though.
+		if ( (node->GetPackageStatus() == EPackageFetchedInstalled) &&
+			( iStateMachine.iInstallManager->IsPackagePresentL(TUid::Uid(node->GetPackageUid())) ) )
+			{
+			SLOG2( "Uninstalling: 0x%x", node->GetPackageUid() );
+
+			iStateMachine.iInstallManager->
+				SilentUninstallPackageAsync( TUid::Uid(node->GetPackageUid()) );
+			// the next event will be triggered by InstallCompleted() below
+			}
+		else
+			{
+			SLOG2( "Skipping: 0x%x", node->GetPackageUid() );
+			// Process the next package
+			iStateMachine.SetState( CStateFactory::EStateUninstallDependency );
+			}
+		}
+	else
+		{
+		SLOG( "About to uninstall wrapper" );
+		// We've processed the dependency tree, uninstall the wrapper
+		// Failure reason is set before calling EPrepareForExitWithError
+		iStateMachine.SetState( CStateFactory::EStateExit );
+		}
+	}
+
+// This is actually handling the UNinstallation completed event
+void TStateUninstallDependency::InstallCompleted(TInt aStatus)
+	{
+	SLOG2( "UninstallDependencyCompleted(): %d", aStatus );
+	// Try to uninstall next dependency, without minding the status code
+	iStateMachine.SetState( CStateFactory::EStateUninstallDependency );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateLaunchApp::TStateLaunchApp(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateLaunchApp::Enter() const
+	{
+	RArray<TUid> appSids;
+	TBool launchStatus = ETrue;
+	// Get the SID list from installer
+	TUid uid = TUid::Uid( iStateMachine.iCurrentPackage->GetPackageUid() );
+	const TBool status = iStateMachine.iInstallManager->GetPackageSidsL(uid, appSids);
+
+	if ( status )
+		{
+#ifdef DEBUG_ADM
+		for (TInt i = 0; i < appSids.Count(); i++)
+			{
+			SLOG3( "SID[%d]=0x%08X", i, appSids[i] );
+			}
+#endif
+		TApaAppInfo appInfo;
+		RApaLsSession lsSession;
+
+		// Connect to Apparc
+		if ( !lsSession.Connect() )
+			{
+			CleanupClosePushL( lsSession );
+
+			for (TInt i = 0; i < appSids.Count(); i++)
+				{
+				TInt ret = lsSession.GetAppInfo( appInfo, appSids[i] );
+				// Get the app Info of the Sid.
+				if ( ret == KErrNone )
+					{
+					HBufC* iconFilename = NULL;
+					// Get the application icon, if any. It's used in the launch dialog.
+					ret = lsSession.GetAppIcon( appSids[i], iconFilename );
+					if (ret == KErrNone)
+						{
+						// We have a launchable exe and icon: get the executable name and caption
+						iStateMachine.iLaunchName = appInfo.iFullName;
+						iStateMachine.iLaunchCaption = appInfo.iCaption;
+						iStateMachine.iLaunchIconFilename.Copy( *iconFilename );
+						SLOG5( "LaunchExe %d '%S' '%S' '%S'", i, &iStateMachine.iLaunchName, &iStateMachine.iLaunchCaption, &iStateMachine.iLaunchIconFilename );
+
+						delete iconFilename;
+						break;
+						}
+					// The .exe didn't have an icon, try next .exe.
+					// We're assuming that only exe's having an icon are the ones we should launch
+					} // if
+				} // for
+			CleanupStack::PopAndDestroy( &lsSession );
+			} //if ( !lsSession.Connect() )
+		else
+			{
+			launchStatus = EFalse;
+			}
+		} // if( status )
+	else
+		{
+		launchStatus = EFalse;
+		}
+
+	appSids.Close();
+
+	if ( launchStatus && iStateMachine.iLaunchName.Length() )
+		{
+		iStateMachine.SetAppLaunch(ETrue);
+		iStateMachine.iAppUi.ShowLaunchPromptL( iStateMachine.iLaunchCaption, iStateMachine.iLaunchIconFilename );
+		}
+	else
+		{
+		// No executable to launch!
+		iStateMachine.SetState( CStateFactory::EStateExit );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void TStateLaunchApp::UserAccepted()
+	{
+	RApaLsSession lsSession;
+
+	// Connect to Apparc
+	User::LeaveIfError( lsSession.Connect() );
+	CleanupClosePushL( lsSession );
+
+	CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+	cmdLine->SetExecutableNameL( iStateMachine.iLaunchName );
+	cmdLine->SetCommandL( EApaCommandRun );
+
+	SLOG3( "Launching %S '%S'", &iStateMachine.iLaunchCaption, &iStateMachine.iLaunchName );
+	// Launch the application
+	// TODO: Better error handling
+	User::LeaveIfError( lsSession.StartApp( *cmdLine ) );
+
+	CleanupStack::PopAndDestroy( 2, &lsSession ); // cmdLine, lsSession
+
+	iStateMachine.SetState( CStateFactory::EStateExit );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void TStateLaunchApp::UserRejected()
+	{
+	SLOG( "User denied application launch" );
+	iStateMachine.SetAppLaunch(EFalse);
+	iStateMachine.SetState( CStateFactory::EStateExit );
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateExit::TStateExit(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateExit::Enter() const
+	{
+	SLOG2( "Exit (%d)", iStateMachine.FailedState() );
+
+#ifdef FEATURE_INSTALL_RESUME
+	// FailedState is checked to differentiate a completion of successful menu launch from failure cases.
+	// Also uninstall the wrapper, when the resume information file is not required
+	// (in case of Bootstrap failure mode - KCmdLineCancelAdmNoResume)
+	if ( ( iStateMachine.FailedState() == CStateFactory::EStateLast ) ||
+			 ( iStateMachine.FailedState() == KUnknownState ) ||
+			 ( !iStateMachine.ResumeRequired() )
+			)
+		{
+		// Do the final cleanup here: remove the wrapper package, which
+		// will also remove the bootstrap
+		SLOG2( "Uninstalling wrapper 0x%08X", iStateMachine.WrapperPackageUid().iUid );
+		const TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage(
+				iStateMachine.WrapperPackageUid() );
+		if (err != KErrNone)
+			{
+			SLOG2( "! Uninstall failed (%d)", err );
+			}
+
+		// Remove resume info files
+		RemoveResumeFiles();
+		}
+	else
+		{
+		// Remove only the bootstrap.
+		// Wrapper is retained for Menu launch.
+		// It is possible that bootstrap is already removed in previous unsuccessful menu launch
+		if ( iStateMachine.iInstallManager->IsPackagePresentL( KUidBootstrap ) )
+			{
+			SLOG2( "Uninstalling bootstrap 0x%08X", KUidBootstrap );
+			const TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage( KUidBootstrap );
+			// ignore any errors
+			if (err != KErrNone)
+				{
+				SLOG2( "! Uninstall failed (%d)", err );
+				}
+			}
+		}
+#else
+	// Do the final cleanup here: remove the wrapper package
+	SLOG2( "Uninstalling wrapper 0x%08X", iStateMachine.WrapperPackageUid().iUid );
+	const TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage(
+			iStateMachine.WrapperPackageUid() );
+	if (err != KErrNone)
+		{
+		SLOG2( "! Uninstall failed (%d)", err );
+		}
+#endif // FEATURE_INSTALL_RESUME
+
+#ifdef FEATURE_REPORTING
+	// Report only the specified cases
+	switch ( iStateMachine.ExitReason() )
+		{
+	case EExitNoError:
+	case EUserCancelled:
+//	case EDownloadFailed:
+	case EInsufficientMemory:
+	case EDeviceNotSupported:
+	case EInstallationFailed:
+	case EInvalidBootstrapVersion:
+	case ERootInstallationFailed:
+		Report();
+		break;
+	default:
+		break;
+		}
+#else
+	// We can exit the application
+	// The default failure reason is "No Error"
+	iStateMachine.iAppUi.ExitApp();
+
+	// Above call does not return
+#endif
+	}
+
+// -----------------------------------------------------------------------------
+// RemoveResumeFiles()
+// On successful completion of the installation process, remove the resume info file.
+// -----------------------------------------------------------------------------
+//
+void TStateExit::RemoveResumeFiles() const
+	{
+	if ( BaflUtils::FileExists(iStateMachine.FsSession(), KADMResumeInfoFile) )
+		{
+		RArray< TPtrC > lineBuffer;
+		TInt ret = 0;
+		HBufC* buffer = ReadConfigFile( iStateMachine.FsSession(), KADMResumeInfoFile, lineBuffer, ret );
+
+		if ( buffer && ret == KErrNone )
+			{
+			// Get AppFileName from the config file
+			TPtrC appFileNameLine = GetConfigValue( KRFieldAppFileName, lineBuffer, ret );
+			if ( ret == KErrNone )
+				{
+				SLOG2( "AppFileName = '%S'", &appFileNameLine );
+
+				if ( BaflUtils::FileExists(iStateMachine.FsSession(), appFileNameLine) )
+					{
+					const TInt err = iStateMachine.FsSession().Delete( appFileNameLine );
+					SLOG2( "AppFile has been deleted (%d)", err);
+					}
+				}
+			else
+				{
+				SLOG2( "Failed to read value from resume info (%d)", ret );
+				}
+			delete buffer;
+			}
+		ret = iStateMachine.FsSession().Delete( KADMResumeInfoFile );
+		SLOG2( "Resume info has been deleted (%d)", ret );
+
+		// TODO: Need to remove the copied dep file as well
+		}
+	}
+#ifdef FEATURE_REPORTING
+// -----------------------------------------------------------------------------
+// Creates a report about the installation and sends that to the server
+// -----------------------------------------------------------------------------
+//
+void TStateExit::Report() const
+	{
+	_LIT8(KFmtVersion, "%d.%02d.%d");
+	_LIT(KOK, "OK");
+	TBuf8<KMaxFileName> url;
+	url.Copy( *iStateMachine.ConfigUrl() );
+
+	// -----------------------------------------------------------------------------
+	// The base report URL is:
+	// http://server/root/x.yy.z/reason/flags/OK
+	//
+	// where
+	//
+	// http://server/root/     ConfigUrl()
+	// x.yy.z                  ADM version formatted as %d.%02d.%d
+	// reason                  iExitReason
+	// flags                   Flags defined below in Report Version 1
+	// OK                      Non-existing file
+	//
+	// -----------------------------------------------------------------------------
+	// Report Version 1
+	//
+	//31        11 10  9  8  7  6  5  4  3  2  1  0
+	// +-------+--+--+--+--+--+--+--+--+--+--+--+--+
+	// |reservd|  |  |                 |           |
+	// +-------+--+--+--+--+--+--+--+--+--+--+--+--+
+	//
+	//      value
+	// bits range  description
+	//  0-3  0-15  Report version
+	//
+	// Other bits for version 1
+	//
+	//      value
+	// bits range  description
+	//  4-9  0-63  Number of packages downloaded
+	//   10   1    Ovi Store running
+	//   11   1    Application launched
+	// -----------------------------------------------------------------------------
+	//
+
+	// Get the ADM version
+	TVersion version;
+	iStateMachine.iInstallManager->GetPackageVersionInfoL(KUidADMApp, version);
+
+#if 0
+	const TUint32 KReportVersion = 1;
+	TUint32 flags;
+	flags  = KReportVersion                                        << 0;  // 4 bits (0-15)
+	flags |= (iStateMachine.iDepTree->CountDownloadNodes() & 0x3f) << 4;  // 6 bits (0-63)
+	flags |= iStateMachine.OviStoreRunning()                       << 10; // 1 bit
+	flags |= iStateMachine.AppLaunch()                             << 11; // 1 bit
+	SLOG2( "Exit: 0x%08x", flags );
+#endif
+
+	url.AppendFormat(KFmtVersion, version.iMajor, version.iMinor, version.iBuild);
+	url.Append('/');
+	url.AppendNum( iStateMachine.ExitReason() );
+	url.Append('/');
+	url.AppendNum( iStateMachine.OviStoreRunning() );
+	url.Append('/');
+	url.AppendNum( iStateMachine.ResumingInstallation() );
+	url.Append('/');
+#if 0
+	url.AppendNumFixedWidthUC(flags, EHex, 8);
+	url.Append('/');
+	url.AppendNum( iStateMachine.OviStoreRunning() );
+	url.Append('/');
+	url.AppendNum( iStateMachine.AppLaunch() );
+	url.Append('/');
+#endif
+	iStateMachine.iDownloadHandler->StartDownloadL(
+		url,
+		KOK,
+		iStateMachine.iDepTree->GetDownloadPath(),
+		0);
+	}
+
+// -----------------------------------------------------------------------------
+// Ignore "in progress" event calls.
+// -----------------------------------------------------------------------------
+//
+void TStateExit::DownloadInProgress(const TInt /* aAlreadyDownloaded */, const TInt /* aDownloadSize */, const TReal32 /* aAvgDlSpeed */)
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// Transfer control to ExitApp().
+// -----------------------------------------------------------------------------
+//
+void TStateExit::DownloadCompleted(const TInt /* aBytesDownloaded */)
+	{
+	iStateMachine.iAppUi.ExitApp();
+	}
+
+// -----------------------------------------------------------------------------
+// Transfer control to ExitApp().
+// -----------------------------------------------------------------------------
+//
+void TStateExit::DownloadFailed()
+	{
+	iStateMachine.iAppUi.ExitApp();
+	}
+
+// -----------------------------------------------------------------------------
+// Transfer control to ExitApp().
+// -----------------------------------------------------------------------------
+//
+void TStateExit::DownloadCancelled()
+	{
+	iStateMachine.iAppUi.ExitApp();
+	}
+#endif
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStatePrepareExitWithError::TStatePrepareExitWithError(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStatePrepareExitWithError::Enter() const
+	{
+	// Show the user a wait note, if needed
+	iStateMachine.iAppUi.HandleFailure();
+
+	// TODO: FIX THIS! DlMgr requires some time for its AOs to do the cleanup.
+	User::After(1000000);
+	iStateMachine.iDownloadHandler->CancelAllDownloads();
+	iStateMachine.iDepTree->RemoveDownloadedFiles( iStateMachine.FsSession() );
+
+#ifdef FEATURE_INSTALL_RESUME
+	// Backup the resume info for future launch
+	if ( iStateMachine.ResumeRequired() )
+		{
+		// Create the resume information
+		if ( CreateInstallationResumeInfo() == KErrNone )
+			{
+			// Dependencies are not uninstalled if launched from Menu
+			iStateMachine.SetState( CStateFactory::EStateExit );
+			return;
+			}
+		}
+	// If no resume info required or CreateInstallationResumeInfo fails.
+	iStateMachine.SetState( CStateFactory::EStateUninstallDependency );
+#else
+	// Trigger the dependency uninstallation
+	iStateMachine.SetState( CStateFactory::EStateUninstallDependency );
+#endif // FEATURE_INSTALL_RESUME
+	}
+
+// -----------------------------------------------------------------------------
+// CreateInstallationResumeInfo
+// Backup the necessary information to continue the installation later i.e.
+// from the application menu grid.
+// -----------------------------------------------------------------------------
+//
+#define CHECK(a) {    \
+	if (a != KErrNone) \
+		goto failed;   \
+	pos++;             \
+	}
+
+TInt TStatePrepareExitWithError::CreateInstallationResumeInfo() const
+	{
+	SLOG( "+ CreateInstallationResumeInfo()" );
+
+	// This is increment in each CHECK() macro
+	TInt pos = 0;
+
+	// Step 0: Backup the required files to ADM Private folder.
+	// (Also the names are written to resume info file)
+	TRAPD( err, BackupFilesL() );
+	CHECK(err);
+
+	RFile outFile;
+	CPackageInfo* node = NULL;
+
+	TInt numberOfNodes = iStateMachine.iDepTree->NodesCount();
+	// Skip the main application
+	if (numberOfNodes > 0)
+		{
+		numberOfNodes--;
+		}
+
+	err = outFile.Open( iStateMachine.FsSession(), KADMResumeInfoFile, EFileWrite | EFileStreamText | EFileShareAny );
+	CHECK(err);
+
+	// Step 1: Write the application name
+	node = iStateMachine.iDepTree->GetRootNode();
+	SLOG3( "Saving state for '%S' (%d)", node->GetPackageName(), numberOfNodes );
+	err = WriteToConfigFile( outFile, KRFieldAppName, *node->GetPackageName() );
+	CHECK(err);
+
+	// Step 2: Write the depPkg UIDs to resume info file.
+	// A new resume info file is already created as part of the "BackupFilesL()"
+	// If user presses cancel before the fetchlist is constructed, then this loop will not execute.
+	for (TInt i = 0; i < numberOfNodes; i++)
+		{
+		node =  iStateMachine.iDepTree->GetFetchNode( i );
+		SLOG2( "Adding info: 0x%08X", node->GetPackageUid() );
+
+		err = WriteIntToConfigFile( outFile, KRFieldDepPkgUid, node->GetPackageUid() );
+		CHECK(err);
+		}
+
+#if 0
+	node = iStateMachine.iDepTree->GetRootNode();
+	SLOG2( "Adding main: 0x%08X", node->GetPackageUid() );
+
+	// Step 3: Write the Root pkg UID to resume info file.
+	// TODO: Check whether this is really needed.
+	err = WriteIntToConfigFile( outFile, KRootPkgUid, node->GetPackageUid() );
+	CHECK(err);
+#endif
+
+	// Step 4: Write the BootstrapVersion to resume info file.
+	err = WriteIntToConfigFile( outFile, KRFieldBootstrap, iStateMachine.BootstrapVersion() );
+	CHECK(err);
+
+	// Step 5: Write the Wrapper installed drive to resume info file.
+	err = WriteIntToConfigFile( outFile, KRFieldWrapperDrive, iStateMachine.iWrapperInstalledDrive );
+	CHECK(err);
+
+	// Step 6: Write the Wrapper Package UID.
+	err = WriteIntToConfigFile( outFile, KRFieldWrapperPkgUid, iStateMachine.WrapperPackageUid().iUid );
+
+	if (err != KErrNone)
+		{
+failed:
+		SLOG3( "Resume info creation failed (%d: %d)", pos, err );
+		// Remove the resume info file in error situation as it might not contain
+		// all the information needed to continue the installation
+		const TInt deleteStatus = iStateMachine.FsSession().Delete(KADMResumeInfoFile);
+		SLOG2( "Resume info has been removed (%d)", deleteStatus );
+		}
+
+	if (pos)
+		{
+		outFile.Close();
+		}
+
+	SLOG2( "- CreateInstallationResumeInfo(): %d", err );
+
+	return err;
+	}
+
+// -----------------------------------------------------------------------------
+// BackupFiles
+// In case of failure during the complete installation process,
+// backup the required files for future launch.
+// -----------------------------------------------------------------------------
+//
+void TStatePrepareExitWithError::BackupFilesL() const
+	{
+#if 0
+	HBufC* destFileName = NULL;
+	TInt err = KErrNone, pos = 0;
+
+	// Backup the main application sis file to a folder. - Copy to ADM Private folder?!
+	TParsePtrC appFileName( *iStateMachine.SisFilename() );
+
+	destFileName = HBufC::NewLC( appFileName.NameAndExt().Length() + KADMPrivatePath().Length() );
+	TPtr nameBufPtr = destFileName->Des();
+
+	nameBufPtr.Append( KADMPrivatePath );
+	nameBufPtr.Append( appFileName.NameAndExt() );
+
+	// TODO: Do the file copying in AO
+	CFileMan* fileMan = CFileMan::NewL( iStateMachine.FsSession() );
+	CleanupStack::PushL(fileMan);
+	err = fileMan->Copy( *iStateMachine.SisFilename(), *destFileName );
+	CleanupStack::PopAndDestroy(fileMan);
+
+	if (err != KErrNone)
+		{
+failed:
+		CleanupStack::PopAndDestroy(destFileName);
+		SLOG3( "Failed to create backup (%d: %d)", pos, err );
+		User::Leave(err);
+		}
+
+	// Backup the info. The file is not present yet.
+	RFile outFile;
+	err = outFile.Replace( iStateMachine.FsSession(), KADMResumeInfoFile, EFileWrite | EFileStreamText | EFileShareAny );
+	CHECK(err);
+
+	// TODO: Backup the depfile in case of Bootstrap version 2 and save the name as well.
+
+	// Write the AppFilename to resume info file.
+	err = WriteToConfigFile( outFile, KAppFileName, destFileName->Des() );
+	CHECK(err);
+	CleanupStack::PopAndDestroy(); // destFileName
+#endif
+	// Backup the info. The file is not present yet.
+	RFile outFile;
+
+	// If no resume info file exists, create a new one.
+	// In case a resume info file exists, replace the file with a new one.
+	// (One resume information file supported at any point of time)
+	TInt err = outFile.Replace( iStateMachine.FsSession(), KADMResumeInfoFile, EFileWrite | EFileStreamText | EFileShareAny );
+
+	if (err != KErrNone)
+		{
+		goto failed;
+		}
+
+	// TODO: Backup the depfile in case of Bootstrap version 2 and save the name as well.
+
+	// Write the AppFilename to resume info file.
+	err = WriteToConfigFile( outFile, KRFieldAppFileName, iStateMachine.SisFilename()->Des() );
+
+	if (err != KErrNone)
+		{
+failed:
+		SLOG2( "- BackupFiles(): LEAVE %d", err );
+		outFile.Close();
+		User::Leave(err);
+		}
+
+	outFile.Close();
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateInstallDependency::TStateInstallDependency(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateInstallDependency::Enter() const
+	{
+	SLOG3( "Installing '%S' to %c:", iStateMachine.iDownloadedFile, (char)iStateMachine.iCurrentPackage->GetInstallDrive() );
+	// Replace the downloading note with installing note
+	iStateMachine.ShowInstallingWaitNoteL( iStateMachine.iCounterCurrent, iStateMachine.iCounterMax );
+	iStateMachine.StopProgressBar();
+
+	// TODO: FIX THIS! This is an ugly hack to give time for S60 DlMgr AOs to
+	// finish their cleanups. To fix this properly, we need to wait till we get
+	// "EHttpDlDeleting" event before starting the installation. This has to be
+	// called before CancelAllDownloads(), otherwise DlMgrServer will die in
+	// CBase91 PANIC.
+	User::After(1000000);
+	// We need to remove the download(s) before starting the installation.
+	// Otherwise we might get KErrInUse error while installing. This happens
+	// quite often when using E: / F: drive as the download drive.
+	iStateMachine.iDownloadHandler->CancelAllDownloads();
+
+	// Wait for the "DlDeleting" event
+	iStateMachine.iDlDeletingSemaphore.Wait(KDlDeletingTimeout);
+
+	iStateMachine.iInstallManager->SilentInstallPackageL(
+			*iStateMachine.iDownloadedFile,
+			iStateMachine.iCurrentPackage->GetInstallDrive()
+		 );
+
+	iStateMachine.UpdateProgressBar(iStateMachine.iCumulativeDepDownloaded,
+			iStateMachine.iProgressMaxValue );
+	}
+
+void TStateInstallDependency::Exit() const
+	{
+	// Remove the wait note
+#if 0
+	if ( !iStateMachine.OviStoreRunning() )
+		{
+		iStateMachine.StopWaitNote();
+		}
+#endif
+	}
+
+void TStateInstallDependency::InstallCompleted(TInt aStatus)
+	{
+	LOG_FUNC
+
+	CPackageInfo *curr = iStateMachine.iDepTree->GetCurrentFetchNode();
+	User::LeaveIfNull(curr);
+	SLOG3( "Removing '%S%S'", &iStateMachine.iDepTree->GetDownloadPath(), curr->GetSisPackageName() );
+
+	// Delete the .sis file as its no longer required.
+	iStateMachine.iDepTree->DeleteFile( iStateMachine.FsSession(),
+					*curr->GetSisPackageName(),
+					iStateMachine.iDepTree->GetDownloadPath()
+					);
+	if (aStatus == KErrNone)
+		{
+		if (curr->GetPackageStatus() == EPackageToBeFetched )
+			{
+			curr->SetPackageStatus(EPackageFetchedInstalled);
+			}
+		else if (curr->GetPackageStatus() == EPackageRootToBeInstalled )
+			{
+			curr->SetPackageStatus(EPackageRootInstalled);
+			}
+		else
+			{
+			SLOG2( "Unexpected package status %d", curr->GetPackageStatus() );
+			}
+
+		// Dependency package succesfully installed, update the counter to keep UI happy
+		iStateMachine.iCounterCurrent++;
+		// Download the next dependency
+		iStateMachine.SetState( CStateFactory::EStateDownloadDependency );
+		}
+	else
+		{
+		SLOG2( "Dependency installation failed %d", aStatus );
+		iStateMachine.SetFailureReason( EInstallationFailed );
+		iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TStateInstallAppSis::TStateInstallAppSis(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateInstallAppSis::Enter() const
+	{
+	// We need to find the root package
+	if (iStateMachine.iCurrentPackage == NULL)
+		{
+		SLOG( "Finding root package" );
+		CPackageInfo* package = NULL;
+		while ( (package = iStateMachine.iDepTree->GetNextFetchNode()) != NULL )
+			{
+			if (package->GetPackageStatus() == EPackageRootToBeInstalled)
+				{
+				SLOG3( "Root: UID 0x%08X, '%S'", package->GetPackageUid(), package->GetPackageName() );
+				break;
+				}
+			}
+		iStateMachine.iCurrentPackage = package;
+		}
+	// iStateMachine.iCurrentPackage should now point to a correct packege,
+	// the application.sis, in this case. Just make sure, it really does that.
+	// Do we have a package set?
+	if ( iStateMachine.iCurrentPackage )
+		{
+		if ( iStateMachine.BootstrapVersion() == 3 )
+			{
+/*
+			SLOG( "Uninstalling smartinstaller (bootstrap)" );
+			TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage(
+					iStateMachine.WrapperPackageUid() );
+			SLOG2( "Uninstall status: %d", err);
+*/
+			// Delete the dependency file that was provided with the wrapper
+			// TODO: Remove if(), DeleteFile() copes with NULL filenames.
+			if ( iStateMachine.DepFilename() )
+				{
+				iStateMachine.iAppUi.DeleteFile( *iStateMachine.DepFilename() );
+				}
+
+#ifdef FEATURE_LAUNCH_INSTALLED_APP
+			SLOG( "Dependencies and application are installed, ready to launch!" );
+			iStateMachine.SetState( CStateFactory::EStateLaunchApp );
+#else
+			SLOG( "Dependencies and application are installed, ready to exit!" );
+			iStateMachine.SetState( CStateFactory::EStateExit );
+#endif
+			}
+		else
+			{
+			SLOG3( "* Installing AppSis 0x%08x '%S'", iStateMachine.iCurrentPackage->GetPackageUid(), iStateMachine.SisFilename() );
+
+			// TODO: Leave or not to leave?
+			//User::LeaveIfNull( iStateMachine.SisFilename() );
+
+			// Update the progress bar
+			iStateMachine.UpdateProgressBar( iStateMachine.iProgressMaxValue,
+				iStateMachine.iProgressMaxValue );
+
+			//First try silent install - if package is self-signed, this will fail
+			//according to policy, so retry with a normal install.
+
+			//User might not have been prompted for drive selection.
+			//In that case, it is ok to prompt for drive selection as part of the Wrapper Package Installation.
+			//This will be the case when files are injected into the Bootstrap import folder and not in a common "?:/ADM" drive.
+
+			TChar installDrive = iStateMachine.SisFilename()->Des()[0];
+			installDrive.UpperCase();
+			if (installDrive < 'A' || installDrive > 'Z')
+				{
+				installDrive = KNoDriveSelected;
+				}
+
+			// If the wrapper installed drive is not selected, use the application.sis
+			// destination drive as the installed drive. This way the developer can
+			// control, if he/she wants to prompt the installation drive or force it
+			// already in the wrapper/installer .pkg file. This can be controlled
+			// by using '!' as the destination drive (=prompt) or by using a fixed
+			// drive letter A->Z (=don't prompt).
+			if ( iStateMachine.iWrapperInstalledDrive == KNoDriveSelected )
+				{
+				iStateMachine.iWrapperInstalledDrive = installDrive;
+				}
+
+			if ( iStateMachine.iWrapperInstalledDrive != KNoDriveSelected )
+				{
+				SLOG3( "Installing AppSis '%S' to %c:", iStateMachine.SisFilename(), (char)iStateMachine.iWrapperInstalledDrive );
+
+				// First show the wait note and then remove progress bar.
+				// MUCH less flicker this way.
+				iStateMachine.ShowWaitNoteL( R_ADM_FINALIZING_INSTALLATION_WAIT_TEXT );
+				iStateMachine.StopProgressBar();
+				iStateMachine.iInstallManager->SilentInstallPackageL( *iStateMachine.SisFilename(), iStateMachine.iWrapperInstalledDrive );
+				}
+			else
+				{
+				SLOG( "! No installation drive selected, prompting" );
+				// User will be prompted for the drive.
+
+				//TODO: This is a hack. Change the Installcompleted logic to accomodate this.
+				iStateMachine.StopWaitNote();
+				iStateMachine.StopProgressBar();
+				TInt aStatus = iStateMachine.iInstallManager->
+						InstallPackage( *iStateMachine.SisFilename() );
+				iStateMachine.SetNonSilentInstallation(ETrue);
+				iStateMachine.HandleInstallCompletedL( aStatus );
+				}
+			} // if
+		}
+	else
+		{
+		// Hmm. We should've had a root package, but apparently we didn't. Odd.
+		SLOG( "! Unexpected root package. PANIC" );
+		PanicInState(EPanicStateUnexpectedRootPackage);
+		}
+	}
+
+void TStateInstallAppSis::InstallCompleted(TInt aStatus)
+	{
+	LOG_FUNC
+
+	//It is possible for silent installation of the main app to fail due to insufficient memory
+	//TODO: would it be wise to move the below conditions to InstallManager and have some different error returned to statemachine?
+
+	if ( ( aStatus == SwiUI::KSWInstErrSecurityFailure ) || ( aStatus == SwiUI::KSWInstErrInsufficientMemory ) )
+		{
+		// We have a wait note displayed. If silent install failed,
+		// it needs to be removed so the installer UI won't be affected.
+		iStateMachine.StopWaitNote();
+
+		//SwiUI collapses the real error, Swi::ESignatureSelfSigned is what we should
+		//be checking here. SwiUI::GetLastErrorL is not implemented
+		//If the silent install fails, because of a self signed package, try again
+		//with interactive install.
+		// This is a synchronous call which returns the control here after
+		// installation is finished (or cancelled, or an error occurs or..)
+		aStatus = iStateMachine.iInstallManager->InstallPackage(
+				*iStateMachine.SisFilename() );
+		iStateMachine.SetNonSilentInstallation(ETrue);
+		}
+	else if ( aStatus == KErrNone )
+		{
+		// We end up here, if the silent installation completes succesfully
+		iStateMachine.SetSilentInstallationOk(ETrue);
+		}
+	// Was installation succesful?
+	if (aStatus == KErrNone)
+		{
+		CPackageInfo *curr = iStateMachine.iDepTree->GetCurrentFetchNode();
+		User::LeaveIfNull(curr);
+		//TODO: What if root package is set in HandleInstallComplete!!!
+		// The next if should _always_ be true here
+		if ( curr->GetPackageStatus() == EPackageRootToBeInstalled )
+			{
+			curr->SetPackageStatus(EPackageRootInstalled);
+			}
+		else if ( curr->GetPackageStatus() != EPackageRootInstalled )
+			{
+			SLOG2( "! Invalid root package status %d", curr->GetPackageStatus() );
+			}
+
+		CPackageInfo* fetchPackage = iStateMachine.iDepTree->GetNextFetchNode();
+
+		// TODO: This is duplicated code from TStateDownloadDependency
+		if ( !fetchPackage )
+			{
+/*
+			//end of list - we're finished
+			SLOG( "Uninstalling wrapper" );
+			TInt err = iStateMachine.iInstallManager->SilentUnInstallPackage(
+					iStateMachine.WrapperPackageUid() );
+			SLOG2( "Uninstall status: %d", err);
+			// Wrapper has been uninstalled, ready to exit
+*/
+#ifdef FEATURE_LAUNCH_INSTALLED_APP
+			iStateMachine.SetState( CStateFactory::EStateLaunchApp );
+#else
+			iStateMachine.SetState( CStateFactory::EStateExit );
+#endif
+			return;
+			}
+		else
+			{
+			// We should be at the end of the list, but seems that we're not.
+			SLOG2( "! Unexpected package 0x%08X. PANIC", fetchPackage->GetPackageUid() );
+			PanicInState(EPanicStateUnexpectedPackage);
+			}
+		}
+	else
+		{
+		const TExitReason reason = (aStatus == SwiUI::KSWInstErrUserCancel)
+				? EUserCancelled
+				: EInstallationFailed;
+		iStateMachine.SetFailureReason( reason );
+		iStateMachine.SetState( CStateFactory::EStatePrepareExitWithError );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// Confirms the user to continue the download when download threshold is exceeded
+// -----------------------------------------------------------------------------
+//
+TStateConfirmDownload::TStateConfirmDownload(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateConfirmDownload::Enter() const
+	{
+	// Show download query as we are roaming
+	iStateMachine.ShowDownloadQueryL( R_ADM_DL_PROMPT_TEXT );
+	// the next state will get invoked by the user reply to the query
+	}
+
+void TStateConfirmDownload::UserAccepted()
+	{
+	// This is called when the user has selected "Yes" in the confirmation query
+	iStateMachine.SetState( CStateFactory::EStateStartDependencyDownload );
+	}
+
+// -----------------------------------------------------------------------------
+// Confirms the user to continue the download if device is roaming
+// -----------------------------------------------------------------------------
+//
+TStateConfirmRoamingDownload::TStateConfirmRoamingDownload(const CStateFactory& aFactory) :
+	TState(aFactory)
+	{
+	}
+
+void TStateConfirmRoamingDownload::Enter() const
+	{
+	// Show download query as we are roaming
+	iStateMachine.ShowDownloadQueryL( R_ADM_DL_PROMPT_TEXT, R_ADM_ROAMING_TEXT );
+	// the next state will get invoked by the user reply to the query
+	}
+
+void TStateConfirmRoamingDownload::UserAccepted()
+	{
+	// This is called when the user has selected "Yes" in the confirmation query
+	iStateMachine.SetState( CStateFactory::EStateStartDependencyDownload );
+	}