smartinstaller/bootstrap/src/bootstrapappui.cpp
author Santosh V Patil <santosh.v.patil@nokia.com>
Fri, 19 Feb 2010 15:03:34 +0530
branchADM
changeset 14 343c622c9f65
permissions -rw-r--r--
Contribution of bootstrap component of the Nokia Smart Installer (beta)

/*
* 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: 
*     CBootstrapAppUi class implementation.
*
*
*/


// INCLUDE FILES
#include <aknglobalnote.h>
#include <stringloader.h>
#include <swinstdefs.h>
#include <swi/sisregistrysession.h>
#include <swi/sisregistryentry.h>
#include <swi/swispubsubdefs.h>
#include <httpdownloadmgrcommon.h>
#include <coeutils.h>
#include <apgcli.h>

#include <SenDomFragment.h>
#include <SenXmlReader.h>
#include <SenElement.h>

#include <centralrepository.h>      // CRepository
#include <browseruisdkcrkeys.h>     // KCRUidBrowser
#include <httpdownloadmgrcommon.h>
#include <es_enum.h>
#include <rconnmon.h>

#include "bootstrapapplication.h"
#include "bootstrapappui.h"
#include "bootstrapconst.h"
#include "bootstrapglobalwaitnoteobserver.h"
#include "bootstrapinstallationobserver.h"
#include "debug.h"
#include "globals.h"
#include "macros.h"
#include "config.h"

// ADM binary name
_LIT(KAdmExePath, "ADM.exe");

_LIT(KDownloadFolder,"?:\\ADM\\");
// Sis file extension
_LIT(KSisExtn,".SIS");
_LIT(KSisxExtn,".SISX");
// Xml file extension
_LIT(KXMLExtn,".XML");
// Dep file extension
_LIT(KDepExtn,"_DEP");
// ADM changes file name
_LIT8(KAdmChangesFile, "adm_changes.xml");

// Logging information
_LIT(KADMLogDir, "ADM");
_LIT(KBootstrapLogFileName, "Bootstraplog.txt" );
_LIT(KBootstrapLogFile, "?:\\logs\\ADM\\Bootstraplog.txt");

// Private folder of SWI Daemon
_LIT(KSWIDaemonPrivateFolder, "\\private\\10202dce\\");
_LIT8(KForwardSlash, "/");

// ADM Uid
const TUid KUidAdm = { 0x2002CCCE };
// Max no of connection attempts to Installer
const TInt KMaxInstallerConnectionAttempts = 6;

// ============================ MEMBER FUNCTIONS ===============================
void CBootstrapAppUi::ConstructL()
	{
	// Create the log
	INIT_DEBUG_LOG( KBootstrapLogFile(), KADMLogDir, KBootstrapLogFileName );

	// Hide from application task list
	HideApplicationFromFSW();

	// Send us to background
	SendToBackgroundL();

	// Initialise app UI with standard value.
	BaseConstructL( ENoScreenFurniture /* CAknAppUi::EAknEnableSkin */ );

	StatusPane()->MakeVisible(EFalse);

	// Wait for the installer to be free
	WaitForInstallCompleteL();

	// Bring us to foreground
	SendToBackgroundL(EFalse);

	// Get the Uid of the latest installed package
	iWrapperPackageUid = GetLatestInstalledL();

	// Connect to the Download Manager
	TBool masterInstance( !iEikonEnv->StartedAsServerApp() );
	iDownloadManager.ConnectL( KUidBootstrapApp, *this, masterInstance );

	// Read the config file
	ReadConfigurationL();

	// Get the dep file and actual application name(if present)
	TRAPD(err, SetFileNameInfoL());
	if (err != KErrNone)
		{
		ExitWithError(R_INSTALLATION_FAILURE_ERR);
		}

#ifdef FEATURE_BOOTSTRAP_SETIAP
	SetIAPL();
#endif

	ShowGlobalWaitNoteL();

	// Create view object

	User::LeaveIfError(iLauncher.Connect());

	LOG("Checking ADM presence in the device");
	iIsAdmInstalled = IsPackagePresentL(KUidAdm, iAdmInstalledVersion);

	LOG( "* State changed to EChangesDownloadState" );
	iAppState = EChangesDownloadState;
	DownloadL();
	}

// -----------------------------------------------------------------------------
// CBootstrapAppUi::CBootstrapAppUi()
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CBootstrapAppUi::CBootstrapAppUi():
						iAllowForeground(EFalse),
						iIsAdmInstalled(EFalse),
						iAdmChangesInfo()
	{
	LOG ( "SmartInstaller starts");
	// disable possible transition effects
	SetFullScreenApp(EFalse);
	}

// -----------------------------------------------------------------------------
// CBootstrapAppUi::~CBootstrapAppUi()
// Destructor.
// -----------------------------------------------------------------------------
//
CBootstrapAppUi::~CBootstrapAppUi()
	{
	LOG( "Bootstrap App ends");
	DELETE_IF_NONNULL( iDepFilename );
	DELETE_IF_NONNULL( iSisFileName );
	delete iGlobalWaitNoteObserver;
	delete iGlobalWaitNote;
	delete iInstallObsrv;
	delete iConfigUrl;
	delete iUrl;
	delete iDownloadFileName;

	iDownloadManager.DeleteAll();
	iDownloadManager.Close();

	iLauncher.Close();

	CLOSE_DEBUG_LOG;
	}

void CBootstrapAppUi::HandleGlobalWaitNoteCancel(const TInt& aStatus)
	{
	LOG3( "+ Cancel note %d, %d", iAppState, aStatus );

	// Do the cleanup based on the state
	if (aStatus == -1)
		{
		iGlobalWaitNoteId = -1;

		switch(iAppState)
			{
			case EInitialState:
				// No CleanUp required here
				break;

			case EChangesDownloadState:
				{
				// Cancel download
				iDownloadManager.ResetAll();
				break;
				}

			case EChangesParseState:
				{
				// Delete the downloaded dep file
				if (iDownloadFileName)
					{
					DeleteFile(*iDownloadFileName);
					}
				}
				// fall-through

			case EADMDownloadState:
				{
				// Cancel download
				iDownloadManager.ResetAll();
				break;
				}

			case EADMInstallState:
				{
				// Cancel installation
				iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentInstall);
				// Delete the downloaded sis file.
				if (iDownloadFileName)
					{
					DeleteFile(*iDownloadFileName);
					}
				}
				// fall-through

			case EADMLaunchState:
				// No CleanUp required here
				break;

			default:
				break;
			}

		TRAP_IGNORE(
			ShowNoteL(EAknGlobalErrorNote, R_INSTALLATION_CANCELLED);
		);

		// Always delete the dep file in case of failure in
		// bootstrap to ensure correct dep file is picked up
		// when the outer package is installed.
		if((KBootstrapVersion == 3)&&(iDepFilename))
			{
			DeleteFile(*iDepFilename);
			}
		else if((KBootstrapVersion == 4)&&(iSisFileName))
			{
			DeleteFile(*iSisFileName);
			}

		// Close the bootstrap application
		CloseApp();
		}
	LOG3( "- Cancel note %d, %d", iAppState, aStatus );
	}

void CBootstrapAppUi::ParseChangesInfoL( const TDesC& aChangesFileName )
	{
	LOG2("+ Parse File ('%S')", &aChangesFileName);

	// Initailize the parser
	CSenXmlReader* XmlReader = CSenXmlReader::NewLC(EErrorOnUnrecognisedTags);
	CSenDomFragment* DomFragment = CSenDomFragment::NewL();
	CleanupStack::PushL(DomFragment);

	XmlReader->SetContentHandler(*DomFragment);
	DomFragment->SetReader(*XmlReader);

	// Parse the provided changes file
	XmlReader->ParseL(CEikonEnv::Static()->FsSession(), aChangesFileName);

	// Get package version
	CSenElement* packageElement;
	packageElement = DomFragment->AsElement().Element(KFieldVersion);
	if (packageElement == NULL)
		{
		User::Leave(EMissingVersion);
		}
	else
		{
		TPtrC8 versionPtr = packageElement->Content();
		TVersion ver;
		if (SetVersion(versionPtr, iAdmChangesInfo.iVersion) == EFalse)
			{
			User::Leave(EInvalidVersion);
			}
		}

	// Get the ADM sis file name
	packageElement = DomFragment->AsElement().Element(KFieldSisName);
	if (packageElement)
		{
		TPtrC8 sisNamePtr = packageElement->Content();
		iAdmChangesInfo.iSisName = sisNamePtr.AllocL();
		}
	else
		{
		User::Leave(EMissingSisFileName);
		}

	//URL read from ADM changes file is disabled.
	//ADM.sis will be fetched from the default config url always...same as ADM_changes.xml
#if 0
	// Get the optional URL
	packageElement = DomFragment->AsElement().Element(KFieldUrl);
	if (packageElement)
		{
		TPtrC8 urlPtr = packageElement->Content();
		iAdmChangesInfo.iUrl = urlPtr.AllocL();
		}
#endif

	CleanupStack::PopAndDestroy( DomFragment ) ;
	CleanupStack::PopAndDestroy( XmlReader ) ;

	LOG( "- ParseChangesInfoL()" );
	}

#ifdef FEATURE_BOOTSTRAP_SETIAP
void CBootstrapAppUi::SetIAPL()
	{
	LOG( "+ CBootstrapAppUi::SetIAPL()" );
	// Use the browser default IAP, if available
	CRepository *repository = CRepository::NewLC( KCRUidBrowser );
	TInt ret, browserIAP;
	ret = repository->Get( KBrowserDefaultAccessPoint, browserIAP );
	CleanupStack::PopAndDestroy( repository );

	LOG3("Browser IAP ID = %d, ret = %d ", browserIAP, ret);
	if ( ( ret != KErrNone ) || ( browserIAP < 0 ) )
		{

		browserIAP = 0;

		}

	//No Browser default IAP. Fetch from connection monitor
	RConnectionMonitor monitor;
	CleanupClosePushL(monitor);

	TUint count;
	TRequestStatus status;

	monitor.ConnectL();
	monitor.GetConnectionCount( count, status );
	LOG2("ConnMon connCount = %d", count);
	User::WaitForRequest( status );
	if ( status.Int() != KErrNone )
		{
		// error
		LOG2("ConnMon.ConnCount() ret = %d, ignoring.", status.Int() );
		}

	// get all available IAPs
	TConnMonIapInfoBuf iapBuf;

	monitor.GetPckgAttribute(  EBearerIdAll,  0, KIapAvailability, iapBuf, status );
	User::WaitForRequest( status ) ;

	if ( status.Int() != KErrNone )
		{
			LOG2("ConnMon.GetAttr() ret = %d, ignoring.", ret);
		}
	else
		{
		TInt countIaps = iapBuf().iCount;
		LOG2("IAP count %d", countIaps);

		// Get the IAPId of the first IAP in the buffer.
		iIAP = iapBuf().iIap[ 0 ].iIapId;

		LOG2("IAP ID[0] is %d", iIAP);

		//Now check whether any IAPId matches BrowserIAP, if yes then set the browserIAP as iIAP
		while( countIaps > 0)
			{
			LOG3("IAP %d: ID = %d", countIaps, iapBuf().iIap[ countIaps ].iIapId);
			if( iapBuf().iIap[ countIaps ].iIapId == browserIAP)
				{
				iIAP = browserIAP;
				break;
				}
				countIaps--;
			}

			LOG2("IAP ID after comparison %d", iIAP);
		}



	if ( iIAP > 0)
		{
#ifdef DO_LOG
			TBuf<64> iapName;
			monitor.GetStringAttribute( iIAP, 0, KIAPName, iapName, status );
			User::WaitForRequest( status );
			if ( status.Int() != KErrNone )
				{
				LOG2( "ConnMon.GetStrAttr() ret = %d, ignoring.", status.Int() );
				}
			LOG3( "Setting DownloadManager IAP to %d ('%S'). No user prompt for IAP.", iIAP, &iapName );
#endif
		// Set the download manager to silent mode
		iDownloadManager.SetBoolAttribute( EDlMgrSilentMode, ETrue );
		iDownloadManager.SetIntAttribute( EDlMgrIap, iIAP );
		}
	//else implies user will be prompted.
		CleanupStack::PopAndDestroy( &monitor );
	}

	LOG( "- CBootstrapAppUi::SetIAPL()" );
	}
#endif
void CBootstrapAppUi::DownloadL()
	{
	LOG2( "+ Download(): %d,", iAppState );

	TPtrC8 filename(NULL,0);
	HBufC8* Url = NULL;

	// Set the download filename and Url based
	// on the state.
	switch(iAppState)
		{
		case EChangesDownloadState:
			{
			filename.Set(KAdmChangesFile);
			Url = iConfigUrl;
			break;
			}
		case EADMDownloadState:
			{
			User::LeaveIfNull(iAdmChangesInfo.iSisName);
			filename.Set((iAdmChangesInfo.iSisName)->Des());
			// If the Url is not provided as part of the changes file,
			// take the default Url
			Url = (iAdmChangesInfo.iUrl==NULL) ?iConfigUrl :iAdmChangesInfo.iUrl;
			break;
			}
		default:
			{
			LOG2( "! Unexpected state: %d", iAppState );
			ExitWithError(R_INSTALLATION_FAILURE_ERR);
			}
		}

	// Create the full URL for download
	DELETE_IF_NONNULL( iUrl);
	iUrl = HBufC8::NewL(Url->Length() + filename.Length() + KForwardSlash().Length() );
	*iUrl = *Url;
	TPtr8 ptr(iUrl->Des());

	// Append forward slash if that's missing
	if (ptr.Right(1) != KForwardSlash)
	   {
	   ptr.Append(KForwardSlash);
	   }
	ptr.Append(filename);


	// Set download file name along with path
	TChar systemDrive;
	RFs::DriveToChar(RFs::GetSystemDrive(),systemDrive);

	DELETE_IF_NONNULL( iDownloadFileName );
	iDownloadFileName = HBufC::NewL(KDownloadFolder().Length() + filename.Length());

	*iDownloadFileName = KDownloadFolder;
	iDownloadFileName->Des()[0] = systemDrive;

	TPtr responseFilenamePtr = iDownloadFileName->Des();

	HBufC* filename16 = HBufC::NewLC(filename.Length());
	filename16->Des().Copy(filename);
	responseFilenamePtr.Append(*filename16);
	CleanupStack::PopAndDestroy(filename16);

	iPausable = EFalse;
	iConnectionAttempts = 0;

	// Create new download
	LOG8_2( "Downloading from URL: '%S'", iUrl );
	LOG2(" Download begins for '%S'", iDownloadFileName );
	TBool isNewDl = ETrue;
	RHttpDownload& dl = iDownloadManager.CreateDownloadL( *iUrl, isNewDl );

	ConeUtils::EnsurePathExistsL(*iDownloadFileName);
	if(isNewDl)
		{
			LOG2( "Response body filename is '%S'", iDownloadFileName );
			dl.SetStringAttribute( EDlAttrDestFilename, *iDownloadFileName );
			dl.Start();
		}

	LOG( "- Download()" );
	}

void CBootstrapAppUi::WaitForInstallCompleteL()
	{
	LOG( "+ WaitForInstallCompleteL()" );

	// Use publish and subscribe mechanism to
	// get notified when installer is free.
	RProperty installComplete;
	User::LeaveIfError( installComplete.Attach(KUidSystemCategory, Swi::KUidSoftwareInstallKey) );

	TInt value;
	if ( installComplete.Get( KUidSystemCategory, Swi::KUidSoftwareInstallKey, value ) == KErrNotFound )
		{
		LOG( "! Could not get installer" );
		installComplete.Close();
		ExitWithError(R_INSTALLATION_FAILURE_ERR);
		}
	else if ( (value & Swi::KSwisOperationMask) == Swi::ESwisNone )
		{
		// Installer is idle.
		}
	else
		{
		LOG( "Waiting for the Installer to finish installation" );
		TRequestStatus status;
		installComplete.Subscribe(status);
		User::WaitForRequest(status);
		}

	iAllowForeground = ETrue;
	LOG( "Installer is idle" );
	installComplete.Close();
	LOG( "- WaitForInstallCompleteL()" );
	}

TUint32 CBootstrapAppUi::GetLatestInstalledL()
	{
	LOG( "+ GetLatestInstalledL()" );

	// Use publish and subscribe mechanism to
	// get Uid of the latest installed package.
	RProperty lastInstall;
	User::LeaveIfError(lastInstall.Attach(KUidSystemCategory, KUidSwiLatestInstallation));

	TInt value = -1;
	if (lastInstall.Get( KUidSystemCategory, KUidSwiLatestInstallation, value ) == KErrNotFound)
		{
		LOG( "! Could not get installer" );
		ExitWithError(R_INSTALLATION_FAILURE_ERR);
		}
	LOG2( "- GetLatestInstalled(): wrapper=0x%08x", value );
	return value;
	}

void CBootstrapAppUi::ShowGlobalWaitNoteL()
	{

	// Allocate TBuf with constant length.
	TBuf<KMaxMsgSize> text( NULL );

	// Reads a resource into a descriptor.
	CEikonEnv::Static()->ReadResource( text, R_ADM_ENV_CREATION_WAIT_TEXT );

	// Create new CAknGlobalNote instance.
	iGlobalWaitNote = CAknGlobalNote::NewL();

	iGlobalWaitNoteObserver = new (ELeave) CGlobalWaitNoteObserver(this);
	iGlobalWaitNoteObserver->iStatus = KRequestPending;
	iGlobalWaitNoteObserver->Start();

	iGlobalWaitNoteId = iGlobalWaitNote->ShowNoteL(
			iGlobalWaitNoteObserver->iStatus,
			EAknGlobalWaitNote,
			text );
	}

void CBootstrapAppUi::StopGlobalWaitNoteL()
	{
	LOG2( "+ CBootstrapAppUi::StopGlobalWaitNoteL(): %d", iGlobalWaitNoteId );
	if(iGlobalWaitNote && (iGlobalWaitNoteId >= 0))
		{
		iGlobalWaitNote->CancelNoteL(iGlobalWaitNoteId);
		}
	iGlobalWaitNoteId = -1;

	DELETE_IF_NONNULL( iGlobalWaitNote         );
	DELETE_IF_NONNULL( iGlobalWaitNoteObserver );
	LOG( "- CBootstrapAppUi::StopGlobalWaitNoteL()" );
	}

void CBootstrapAppUi::HandleDMgrEventL( RHttpDownload& aDownload, THttpDownloadEvent aEvent )
	{
	LOG3("+HandleDMgrEventL(): DlState=%d, ProgState=%d", aEvent.iDownloadState, aEvent.iProgressState);

	TInt32                      tmp;
	THttpDownloadMgrError       dlErrorId;
	TInt32                      sysErrorId( KErrNone );

	// If DL is in final state (complete/fail), there's an error id available.
	// TODO: Handle error condition
	TInt sysErr = aDownload.GetIntAttribute( EDlAttrGlobalErrorId ,sysErrorId );
	TInt dlErr = aDownload.GetIntAttribute( EDlAttrErrorId ,tmp );
	dlErrorId = (THttpDownloadMgrError)tmp;

	//TODO: Include Log5
	//LOG5( "SysErrId=%d, DlErrId=%d. DlSize=%d, CntSize=%d.", sysErrorId, dlErrorId, downloadedsize, contentsize );

	switch ( aEvent.iDownloadState )
		{
		case EHttpDlCreated:
			{
			break;
			}
		case EHttpDlInprogress:
			{
			switch ( aEvent.iProgressState)
				{
				case EHttpProgCreatingConnection:
					{
					break;
					}
				case EHttpProgConnected:
					{
					break;
					}
				case EHttpProgConnectionSuspended:
				case EHttpProgDisconnected:
					{
					// Try to reconnect if:
					// 1. No of connection attempts is less than KMaxDlConnectionAttempts
					// 2. IAP selection dialog is not cancelled.
					if ((iConnectionAttempts < KMaxDlConnectionAttempts)
					&& !(dlErrorId == EConnectionFailed && sysErrorId == KErrCancel))
						{
						++iConnectionAttempts;
						LOG2("Restart attempt is '%d'",iConnectionAttempts);
						aDownload.Start();
						}
					break;
					}
				case EHttpProgDownloadStarted:
					{
					break;
					}
				case EHttpContentTypeRequested:
					{
					break;
					}
				case EHttpProgResponseHeaderReceived:
					{
					break;
					}
				case EHttpProgResponseBodyReceived:
					{
					break;
					}
				default :
					break;
				}
			break;
			}
		case EHttpDlPausable:
			{
			iPausable = ETrue;
			break;
			}
		case EHttpDlNonPausable:
			{
			iPausable = EFalse;
			break;
			}
		case EHttpDlCompleted:
			{
			iDownloadManager.GetIntAttribute( EDlMgrIap, iIAP );
			LOG2("IAP set to %d", iIAP);

			HandleHttpFetchCompleteL(EFalse);
			break;
			}
		case EHttpDlPaused:
			{
			if((dlErrorId == EConnectionFailed) && (sysErrorId == KErrCancel))
				{
				isIapCancelled = 1;
				}

			// Continue dowload if paused in EHttpContentTypeReceived
			if(aEvent.iProgressState == EHttpContentTypeReceived)
				{
				aDownload.Start();
				}
			// Try to reconnect if:
			// 1. No of connection attempts is less than KMaxDlConnectionAttempts
			// 2. IAP selection dialog is not cancelled.
			else if((iConnectionAttempts < KMaxDlConnectionAttempts)
					&& (!isIapCancelled))
				{
				aDownload.Start();
				}
			else if(iPausable)
				{
				aDownload.Start();
				}
			else
				{
				HandleHttpFetchCompleteL(ETrue);
				}
			break;
			}
		case EHttpDlFailed:
			{
			if((dlErrorId == EConnectionFailed) && (sysErrorId == KErrCancel))
				{
				isIapCancelled = 1;
				}

			HandleHttpFetchCompleteL(ETrue);
			break;
			}
		case EHttpDlDeleting:
			{
			break;
			}
		case EHttpDlDeleted:
			{
			break;
			}
		default:
			{
			break;
			}
		}
	}


void CBootstrapAppUi::HandleHttpFetchCompleteL(const TBool& aStatus)
	{
	LOG3( "+ Fetch(): s=%d, a=%d", aStatus, iAppState );

	User::LeaveIfNull(iDownloadFileName);

	if (aStatus == EFalse)
		{
		switch(iAppState)
			{
			case EChangesDownloadState:
				{
				// Parse downloaded changes file
				iAppState = EChangesParseState;
				LOG("* State changed to EChangesParseState");

				TRAPD(err, ParseChangesInfoL(*iDownloadFileName));
				LOG2( "Changes file parsing completed with status: %d", err);

				// Delete no longer required changes file
				DeleteFile(*iDownloadFileName);

				// 1. Install ADM if not already present
				// 2. Upgrade ADM if higher version is available
				// 3. If the upgrade fails, launch the current version
				//    of ADM in device.
				TBool isAdmDownloadRequired = CompareVersions(iAdmInstalledVersion, iAdmChangesInfo.iVersion)
												== EGreaterSecondVersion;

				if ((err==KErrNone) && isAdmDownloadRequired)
					{
					LOG( "* Changing state to EADMDownloadState" );
					iAppState = EADMDownloadState;
					DownloadL();
					}
				else if (iIsAdmInstalled)
					{
					LOG( "* Changing state to EADMLaunchState" );
					iAppState = EADMLaunchState;
					TRAPD( err, LaunchAdmL() );
					if (err != KErrNone)
						{
						LOG2( "ADM launch fail %d", err );
						ExitWithError(R_INSTALLATION_FAILURE_ERR);
						}
					LOG( "ADM launched OK, exiting! 1" );
					TRAP_IGNORE( StopGlobalWaitNoteL() );
					CloseApp();
					}
				else
					{
					// Adm changes file parse error
					ExitWithError(R_INSTALLATION_FAILURE_ERR);
					}
				break;
				}

			case EADMDownloadState:
				{
				LOG2( "ADM downloaded OK: '%S'", iDownloadFileName);

				iAppState = EADMInstallState;
				LOG( "* State changed to EADMInstallState" );
				AsyncInstallPackageL(*iDownloadFileName);
				break;
				}

			default:
				{
				LOG2( "Unexpected state %d", iAppState );
				// Unexpected State
				ExitWithError(R_INSTALLATION_FAILURE_ERR);
				}
			}
		}
	else
		{
		// Launch existing version of ADM (if present) in device
		// in case of download failure.
		if (iIsAdmInstalled && (!isIapCancelled))
			{
			LOG( "* Changing state to EADMLaunchState" );
			iAppState = EADMLaunchState;
			TRAPD(err, LaunchAdmL());
			if (err != KErrNone)
				 {
				 ExitWithError(R_INSTALLATION_FAILURE_ERR);
				 }
			LOG( "ADM launched OK, exiting! 2" );
			TRAP_IGNORE( StopGlobalWaitNoteL() );
			CloseApp();
			}
		else
			{
			LOG( "! ADM download failed!" );
			ExitWithError(R_HTTP_TRANSACTION_ERR);
			}
		}

	LOG( "- Fetch complete ");
	}

void CBootstrapAppUi::SetFileNameInfoL()
	{
	LOG( "+ SetFileNameInfoL()" );
	LOG2( "Bootstrap version: %d", KBootstrapVersion);

	if(KBootstrapVersion<1 && KBootstrapVersion>4)
		{
		// Unsupported Bootstrap version
		User::Leave(KErrNotSupported);
		}

	// Connect to SisRegistry to fetch Package info
	Swi::RSisRegistrySession registrySession;
	User::LeaveIfError(registrySession.Connect());
	CleanupClosePushL(registrySession);

	Swi::RSisRegistryEntry entry;

	// Open registry entry
	User::LeaveIfError(entry.Open(registrySession, TUid::Uid(iWrapperPackageUid)));
	CleanupClosePushL(entry);

	RPointerArray<HBufC> packageFiles;
	entry.FilesL(packageFiles);
	const TInt filesCount(packageFiles.Count());

	// look into the files installed as part of the package,
	// to find the dep file name and actuall application file name.
	for (TInt i=0; i<filesCount; i++)
		{
		TParse parse;
		TInt err = parse.Set(packageFiles[i]->Des(), NULL, NULL);
		if (err != KErrNone)
			{
			continue;
			}
		TPtrC orgExtn = parse.Ext();

		if (orgExtn.Length() == 0)
			{
			continue;
			}

		HBufC* extn = orgExtn.AllocLC();
		TPtr extnPtr = extn->Des();
		extnPtr.UpperCase();

		if(KBootstrapVersion != 3)
			{
			if ((extnPtr.Compare(KSisExtn) == 0)||(extnPtr.Compare(KSisxExtn) == 0))
				{
				TPtrC privatePath( KNullDesC );
				const TInt driveLength = 2;
				if (packageFiles[i]->Length() > (KSWIDaemonPrivateFolder().Length() + driveLength))
					{
					privatePath.Set( packageFiles[i]->Des().Mid( driveLength ) );
					privatePath.Set( privatePath.Left( KSWIDaemonPrivateFolder().Length() ) );
					}

				// Ignore if its a Stub Sis file
				if(privatePath.CompareF(KSWIDaemonPrivateFolder))
					{
					if (iSisFileName == NULL)
						{
						iSisFileName = packageFiles[i]->AllocL();
						LOG2( "Actual application name is '%S'", iSisFileName);
						}
					else
						// More than one sis present in the Wrapper Pkg
						{
					LOG2( "! More than one sis file present: '%S'. LEAVE.", packageFiles[i] );

					User::Leave(KErrNotSupported);
						}
					}
				}//end of sis extension
			}//end of Bootstrapversion 2
		if (KBootstrapVersion != 4)
			{
			if(extnPtr.Compare(KXMLExtn) == 0)
				{
				TPtrC orgName = parse.Name();
				const TInt namelength = orgName.Length();
				const TInt depSuffixlength = KDepExtn().Length();

				if (namelength > depSuffixlength)
					{
					TPtrC depSuffix = orgName.Mid((namelength-depSuffixlength), depSuffixlength);

					HBufC* name = depSuffix.AllocLC();
					TPtr namePtr = name->Des();
					namePtr.UpperCase();

					if (namePtr.Compare(KDepExtn) == 0)
						{
						if (iDepFilename == NULL)
							{
							iDepFilename = packageFiles[i]->AllocL();
							LOG2( "Dep file name is '%S'", iDepFilename);
							}
						else
							// More than one dep file present in the Wrapper Pkg
							{
							LOG2( "! More than one dep file present: '%S'. LEAVE.", packageFiles[i] );
							User::Leave(KErrNotSupported);
							}
						}
					CleanupStack::PopAndDestroy(name);
					}
				}
			}
		CleanupStack::PopAndDestroy(extn);
		}

	packageFiles.ResetAndDestroy();
	packageFiles.Close();

	if(KBootstrapVersion != 3)
		{
		User::LeaveIfNull(iSisFileName);
		if (!(ConeUtils::FileExists(*iSisFileName)))
			{
			User::Leave(KErrNotFound);
			}
		}
	if(KBootstrapVersion != 4)
		{
		User::LeaveIfNull(iDepFilename);
		}

	CleanupStack::PopAndDestroy(&entry);
	CleanupStack::PopAndDestroy(&registrySession);

	LOG( "- SetFileNameInfoL()" );
	}

TInt CBootstrapAppUi::LaunchAdmL()
	{
	LOG( "+ LaunchAdmL()" );

	// In case of approach 3 , cleanup of only BootStrap
	// is required.
	if (KBootstrapVersion == 3)
	   {
	   iWrapperPackageUid = KUidBootstrapApp.iUid;
	   }

#ifdef __USE_RAPA
	HBufC *processArgs = HBufC::NewLC(iDepFilename->Length() + iSisFileName->Length() + 10 + 3 + 2);
	TPtr cmdLineParams = processArgs->Des();
	cmdLineParams.Append(iDepFilename->Des());
	cmdLineParams.Append(' ');
	cmdLineParams.Append(iSisFileName->Des());
	cmdLineParams.Append(' ');
	cmdLineParams.AppendNum(iWrapperPackageUid);
	cmdLineParams.Append(' ');
	cmdLineParams.AppendNum(iIAP);
	HBufC *tmp = HBufC::NewLC( cmdLineParams.Length() );
	tmp->Des().Copy( cmdLineParams );
	LOG2( "cmdLineParams '%S'", tmp );
	CleanupStack::PopAndDestroy(tmp);
	TApaAppInfo appInfo;
	RProcess process;
	RApaLsSession appArcSession;
	User::LeaveIfError( appArcSession.Connect() );
	LOG("RApaLsSession.Connect() OK");
	CleanupClosePushL<RProcess>( process );
	CleanupClosePushL<RApaLsSession>( appArcSession );
	User::LeaveIfError( appArcSession.GetAppInfo( appInfo, KUidAdm ) );
	LOG("RApaLsSession.GetAppInfo() OK");
	TFileName appName = appInfo.iFullName;
	LOG2("RApaLsSession: iFullName='%S'", &appName);
	User::LeaveIfError( process.Create( appName, processArgs->Des() ) );
	HBufC8 *tail = HBufC8::NewLC( processArgs->Length() );
	tail->Des().Copy(processArgs->Des());
	CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
	cmdLine->SetExecutableNameL( appName );
	cmdLine->SetCommandL( EApaCommandBackground );
	cmdLine->SetTailEndL( tail->Des() );
	cmdLine->SetProcessEnvironmentL( process );
	LOG("RApaLsSession: going to launch");
	User::LeaveIfError( appArcSession.StartApp( *cmdLine ) );
	process.Resume();
	CleanupStack::PopAndDestroy( cmdLine );
	CleanupStack::PopAndDestroy( tail );
	CleanupStack::PopAndDestroy( &appArcSession );
	CleanupStack::PopAndDestroy( &process );
	CleanupStack::PopAndDestroy( processArgs );
	LOG("launch OK");
#else
	// Create ADM command line:
	// adm.exe dependency_filename sis_filename uid_in_dec
	//
	// Size of 32-bit Bootstrap Version Value is 10 characters
	// Size of 32-bit UID when converted to numeric string is 10 characters (4294967295)
	// Max size of iIAP(TInt) when converted to numeric string is 10 characters
	// Size of 2 spaces is 2 characters
	const TInt mandatoryOptionsLength = 10+ 10+ 10+ 2;
	TBufC<mandatoryOptionsLength> mandatoryOptions;
	TPtr mandatoryOptionsPtr = mandatoryOptions.Des();

	mandatoryOptionsPtr.AppendNum(KBootstrapVersion);
	mandatoryOptionsPtr.Append(' ');
	mandatoryOptionsPtr.AppendNum(iWrapperPackageUid);
	mandatoryOptionsPtr.Append(' ');
	mandatoryOptionsPtr.AppendNum(iIAP);

	HBufC *processArgs  = NULL;

	switch (KBootstrapVersion)
		{
		case 1:
		case 2:
			{
			User::LeaveIfNull(iSisFileName);
			User::LeaveIfNull(iDepFilename);
			// Size of 2 spaces is 2 characters
			processArgs = HBufC::NewLC(
								mandatoryOptionsLength +
								iDepFilename->Length() +
								iSisFileName->Length() +
								2);
			TPtr cmdLine = processArgs->Des();
			cmdLine.Append(mandatoryOptionsPtr);
			cmdLine.Append(' ');
			cmdLine.Append(*iDepFilename);
			cmdLine.Append(' ');
			cmdLine.Append(*iSisFileName);
			break;
			}
		case 3:
			{
			User::LeaveIfNull(iDepFilename);
			// Size of 1 spaces is 1 characters
			processArgs = HBufC::NewLC(
								mandatoryOptionsLength +
								iDepFilename->Length() +
								1);
			TPtr cmdLine = processArgs->Des();
			cmdLine.Append(mandatoryOptionsPtr);
			cmdLine.Append(' ');
			cmdLine.Append(*iDepFilename);
			break;
			}
		case 4:
			{
			User::LeaveIfNull(iSisFileName);
			// Size of 1 spaces is 1 characters
			processArgs = HBufC::NewLC(
								mandatoryOptionsLength +
								iSisFileName->Length() +
								1);
			TPtr cmdLine = processArgs->Des();
			cmdLine.Append(mandatoryOptionsPtr);
			cmdLine.Append(' ');
			cmdLine.Append(*iSisFileName);
			break;
			}
		default:
			// Unsupported Bootstrap Version
			ExitWithError(R_INSTALLATION_FAILURE_ERR);
			break;
		}

	// Launch ADM
	LOG3( "Launching %S '%S'", &KAdmExePath, processArgs);

	RProcess process;
	CleanupClosePushL<RProcess>( process );

	const TInt err = process.Create( KAdmExePath, processArgs->Des() );
	if (err != KErrNone)
		{
		LOG2( "ADM launch failed with error: %d", err );
		CleanupStack::PopAndDestroy( &process );
		CleanupStack::PopAndDestroy( processArgs );
		ExitWithError(R_INSTALLATION_FAILURE_ERR);
		}

	process.SetPriority( EPriorityBackground );
	process.Resume();
#if 0
	const TInt type = process.ExitType();
	const TInt reason = process.ExitReason();
	TExitCategoryName cat = process.ExitCategory();
	LOG4( "Exit type %d, reason %d, cat '%S'", type, reason, &cat);
#endif
	CleanupStack::PopAndDestroy( &process );
	CleanupStack::PopAndDestroy( processArgs );

#endif // if __USE_RAPA
	LOG2( "- LaunchAdmL(): %d", err );
	return KErrNone;
	}

void CBootstrapAppUi::AsyncInstallPackageL(const TDesC& aResponseFilename)
	{
	SwiUI::TInstallOptions Options;

	Options.iUpgrade = SwiUI::EPolicyAllowed;
	Options.iOCSP    = SwiUI::EPolicyNotAllowed;
	Options.iDrive   = 'c';
	Options.iUntrusted = SwiUI::EPolicyNotAllowed;
	Options.iCapabilities = SwiUI::EPolicyNotAllowed;
	Options.iOverwrite = SwiUI::EPolicyAllowed;

	iOptionsPckg = Options;

	if (iInstallObsrv == NULL)
		{
		iInstallObsrv = new (ELeave) CInstallObserver(this);
		}
	iInstallObsrv->iStatus = KRequestPending;
	iInstallObsrv->Start();
	// Start asynchronous installation
	iLauncher.SilentInstall(iInstallObsrv->iStatus, aResponseFilename, iOptionsPckg);
	}

void CBootstrapAppUi::HandleInstallCompleteL(const TInt& aStatus)
	{
	LOG2("+ HandleInstallCompleteL(%d)", aStatus);
	User::LeaveIfNull(iDownloadFileName);

	// If the install server is busy , try connecting multiple times.
	if (aStatus == SwiUI::KSWInstErrBusy && ((++iInstallAttempt) <= KMaxInstallerConnectionAttempts))
		{
		LOG2( "Retrying installation %d", aStatus );
		AsyncInstallPackageL(*iDownloadFileName);
		}
	else
		{
		LOG2("ADM installation status: %d", aStatus);

		LOG("Deleting ADM sis file");
		// Delete no longer required sis file.
		DeleteFile(*iDownloadFileName);

		if (aStatus == KErrNone || iIsAdmInstalled)
			{
			iAppState = EADMLaunchState;
			TRAPD( err, LaunchAdmL() );
			if ( err != KErrNone )
				{
				LOG2( "ADM launch failed %d", err );
				ExitWithError(R_INSTALLATION_FAILURE_ERR);
				}
			LOG2( "ADM launched OK %d", err );
			TRAP_IGNORE( StopGlobalWaitNoteL() );
			CloseApp();
			}
		else
			{
			ExitWithError(R_INSTALLATION_FAILURE_ERR);
			}
		}
	LOG("- HandleInstallCompleteL()");
	}

TBool CBootstrapAppUi::IsPackagePresentL(const TUid& aUid, TVersion& aVersion)
	{
	LOG( "+ ADMPresent()");

	// Connect to SisRegistry to find if the package is
	// already installed.
	Swi::RSisRegistrySession registrySession;

	User::LeaveIfError(registrySession.Connect());
	CleanupClosePushL(registrySession);

	const TBool isPkgInstalled = registrySession.IsInstalledL(aUid);

	if (isPkgInstalled)
		{
		Swi::RSisRegistryEntry entry;

		// Open registry entry
		User::LeaveIfError(entry.Open(registrySession, aUid));
		CleanupClosePushL(entry);
		aVersion = entry.VersionL();

		CleanupStack::PopAndDestroy(&entry);
		}

	CleanupStack::PopAndDestroy(&registrySession);

	LOG3( "- ADMPresent(): 0x%x = %d", aUid.iUid, isPkgInstalled );

	return isPkgInstalled;
	}

void CBootstrapAppUi::DeleteFile(const TDesC& aFileName)
	{
	CCoeEnv::Static()->FsSession().Delete(aFileName);
	}

void CBootstrapAppUi::ShowNoteL( const TAknGlobalNoteType& aType , const TInt& aResourceId )
	{
	// Allocate TBuf with constant length.
	TBuf<KMaxMsgSize> text;

	// Reads a resource into a descriptor.
	CEikonEnv::Static()->ReadResource( text, aResourceId );

	// Create new CAknGlobalNote instance.
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL( aType , text );
	CleanupStack::PopAndDestroy(globalNote);
	}

void CBootstrapAppUi::ExitWithError(const TInt& aResourceId )
	{
	LOG2( "+ ExitWithError(): 0x%08x", aResourceId );

	// Display error message
	TRAP_IGNORE(
		StopGlobalWaitNoteL();
		ShowNoteL(EAknGlobalErrorNote, aResourceId);
	);

	// Delete the dep file is present
	if((KBootstrapVersion == 3)&&(iDepFilename))
		{
		DeleteFile(*iDepFilename);
		}
	else if((KBootstrapVersion == 4)&&(iSisFileName))
		{
		DeleteFile(*iSisFileName);
		}

	RunAppShutter();
	Exit();

	LOG( "- ExitWithError()" );
	}

void CBootstrapAppUi::CloseApp()
	{
	LOG( "+ CloseApp()" );

	RunAppShutter();
	Exit();

	LOG( "- CloseApp()" );
	}

void CBootstrapAppUi::HandleForegroundEventL(TBool aForeground)
	{
	LOG3("+ CBootstrapAppUi::HandleForegroundEventL(%d): allow=%d", aForeground, iAllowForeground);
	CAknAppUi::HandleForegroundEventL(aForeground);
	if (aForeground && !iAllowForeground)
		{
		SendToBackgroundL();
		}
	LOG("- CBootstrapAppUi::HandleForegroundEventL()" );
	}

// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
void CBootstrapAppUi::SendToBackgroundL(TBool aBackground)
	{
	LOG2( "+ SendToBackgroundL(%d)", aBackground );
	// We have gained the focus
	RWsSession aWsSession;
	User::LeaveIfError( aWsSession.Connect() );
	TApaTask task(aWsSession);

	// Initialise the object with the window group id of
	// our application (so that it represent our app)
	task.SetWgId(CEikonEnv::Static()->RootWin().Identifier());
	if (aBackground)
		{
		task.SendToBackground();
		}
	else
		{
		task.BringToForeground();
		}
	aWsSession.Close();
	LOG( "- SendToBackgroundL() ");
	}

void CBootstrapAppUi::HandleCommandL(TInt aCommand)
	{
	switch (aCommand)
		{
		case EEikCmdExit:
		case EAknSoftkeyExit:
			Exit();
			break;

		default:
			break;
		}
	}

// ---------------------------------------------------------------------------
// CBootstrapAppUi::ReadConfigurationL
// Leaves if runs out of memory
//
// @return KErrNone if configuration was read correctly, error code otherwise
// ---------------------------------------------------------------------------
//
TInt CBootstrapAppUi::ReadConfigurationL()
	{
	TFileName configFile;
	RArray< TPtrC > lineBuffer;
	TInt ret( KErrNone );
	RFs& rfs = CEikonEnv::Static()->FsSession();

	// Find the configuration file from the private directory
	ret = rfs.PrivatePath(configFile);
	if (ret == KErrNone)
		{
		TBuf<2> appDrive;
		// Insert the drive of the running application
		appDrive.Copy(Application()->AppFullName().Left(2));
		configFile.Insert(0, appDrive);
		// Append the configuration file name
		configFile.Append(KConfigFile);

		LOG2( "configFile = %S", &configFile );

		HBufC* buffer = ReadConfigFile(rfs, configFile, lineBuffer, ret );

		if ( buffer && ret == KErrNone )
			{
			// Get Url from the config file
			TPtrC urlLine = GetConfigValue( KCfgTagUrl, lineBuffer, ret );
			if ( ret == KErrNone )
				{
				iConfigUrl = HBufC8::NewL(urlLine.Length());
				iConfigUrl->Des().Copy(urlLine);
				LOG8_2( "configUrl = %S", iConfigUrl );
				}
			delete buffer;
			}
		}
		if ( !iConfigUrl )
			{
			// Error occured while reading the configuration, use default URL
			iConfigUrl = HBufC8::NewL(KDefaultDepServerUrl().Length());
			*iConfigUrl = KDefaultDepServerUrl;
			LOG8_2( "configUrl = %S (default)", iConfigUrl );
			}

	lineBuffer.Close();

	return ret;
	}