smartinstaller/adm/src/ADMAppUi.cpp
author Santosh V Patil <santosh.v.patil@nokia.com>
Wed, 30 Jun 2010 11:01:26 +0530
branchADM
changeset 48 364021cecc90
permissions -rw-r--r--
SmartInstaller contribution based on the Nokia Qt SDK 1.0 release

/*
* 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: 
*     CADMAppUi implementation
*
*
*/


// INCLUDE FILES
#include <ADM.rsg>
#include <ADM.mbg>
#include <bacline.h>
#include <COEUTILS.H>
#include <mmtsy_names.h>    // Phone information
#include <hal.h>            // Hal::GetData()
#include <PathInfo.h>       // PathInfo::
#include <sysutil.h>        // SysUtil::DiskSpaceBelowCriticalLevel(), GetSWVersion()
#include <stringloader.h>   // StringLoader::LoadLC()
#include <aknquerydialog.h>
#include <aknnotewrappers.h>
#include <avkon.rsg>        // Default dialogs
#include <BAUTILS.H>
#include <rconnmon.h>
#include "ADM.hrh"
#include "ADM.pan"
#include "ADMApplication.h"
#include "ADMAppUi.h"
#include "ADMStateMachine.h"
#include "ADMXmlParser.h"
#include "ADMSisParser.h"
#include "ADMPackageInfo.h"
#include "ADMDownloadHandler.h"
#include "ADMInstallManager.h"
#include "networkstatuslistener.h"

#include "debug.h"
#include "globals.h"
#include "config.h"
#include "macros.h"
#include "utils.h"

#ifdef USE_LOGFILE
_LIT(KADMLogDir, "ADM");
_LIT(KADMLogFileName, "log.txt" );
_LIT(KADMLogFile, "?:\\logs\\ADM\\log.txt");
#endif

/**
 * Download path for dependency packages
 */
_LIT(KADMFolderPath,"?:\\system\\adm\\");

// ============================ MEMBER FUNCTIONS ===============================
void CADMAppUi::ConstructL()
	{
	LOG( "+ CADMAppUi::ConstructL()" );

	// Hide from application task list
	HideApplicationFromFSW();

	// Initialise app UI with standard value.
	BaseConstructL( ENoScreenFurniture /*CAknAppUi::EAknEnableSkin*/);
	StatusPane()->MakeVisible(EFalse);

	// Set download path
	TChar systemDrive;
	RFs::DriveToChar(RFs::GetSystemDrive(), systemDrive);
	HBufC* downloadPath = KADMFolderPath().AllocLC();
	downloadPath->Des()[0] = systemDrive;

	// Create the state machine
	iStateMachine = CStateMachine::NewL(*this, *downloadPath);

	iRfs = iEikonEnv->FsSession();

	iOviStoreRunning = CUtils::OviStoreRunning();

	// Process command line arguments
	ProcessCommandLineArgsL();

	iProgress = CProgressDialog::NewL(*this);

	// If we don't have exit reason set, we can show the progress already
	if (iExitReason == EExitNoError)
		{
		// Show progress bar with little progress already early on
		const TInt waitNoteRes = iResumingInstallation
				? R_ADM_CONTINUING_INST_TEXT
				: R_ADM_VERIFYING_SW_TEXT;
		ShowGlobalProgressL( waitNoteRes, 1, 10 );
		}

	iSwVersion = HBufC::NewL(KSysUtilVersionTextLength);

	// Initialize the telephone server
	User::LeaveIfError( iTelServer.Connect() );
	User::LeaveIfError( iTelServer.LoadPhoneModule( KMmTsyModuleName ) );
	User::LeaveIfError( iPhone.Open( iTelServer, KMmTsyPhoneName ) );

	// Get device information
	User::LeaveIfError( GetPhoneInformation() );

	// Ignore the return code. Default URL will be used if error happens (leaves if no memory)
	ReadConfigurationL();

	ReadStaticResourcesL();

	// Kick the state machine running
	iStateMachine->Start();

	CleanupStack::PopAndDestroy(downloadPath);

	LOG( "- CADMAppUi::ConstructL()" );
	}

// -----------------------------------------------------------------------------
// CADMAppUi::CADMAppUi()
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CADMAppUi::CADMAppUi() :
		iExitReason(EExitNoError),
		iIAP(KInvalidIapId),
		iIsResumeRequired(ETrue)
	{
	// disable possible transition effects
	SetFullScreenApp(EFalse);
	INIT_DEBUG_LOG( KADMLogFile(), KADMLogDir, KADMLogFileName );
	LOG( "CADMAppUi::CADMAppUi()" );
	// Restore our thread priority to normal, we have been launched
	// with EPriorityBackground
//	RThread().SetPriority(EPriorityNormal);
	}

// -----------------------------------------------------------------------------
// CADMAppUi::~CADMAppUi()
// Destructor.
// -----------------------------------------------------------------------------
//
CADMAppUi::~CADMAppUi()
	{
	LOG( "CADMAppUi::~CADMAppUi()" );

	// Stop the state machine
	iStateMachine->Stop();

	// Just be make sure that all global stuff is out from the screen
	CancelProgressBar();
	CancelWaitNote();

	iPhone.Close();
	iTelServer.Close();

	DELETE_IF_NONNULL( iQueryMessage            );
	DELETE_IF_NONNULL( iGlobalConfirmationQuery );
	DELETE_IF_NONNULL( iGlobalQueryObserver     );
	delete iAppIconFilename;
	delete iMainAppName;
	delete iConfigUrl;
	delete iSwVersion;
	delete iProgress;
	delete iDepFileName;
	delete iSisFileName;
	delete iStateMachine;

	CLOSE_DEBUG_LOG;
	}

// -----------------------------------------------------------------------------
// Processes the command line parameters and sets state machine initial
// state according to the parameters.
//
// Requires that the state machine has been instantiated (iStateMachine).
// -----------------------------------------------------------------------------
//
void CADMAppUi::ProcessCommandLineArgsL()
	{
	LOG( "+ ProcessCommandLineArgsL()" );
	CCommandLineArguments* args = CCommandLineArguments::NewLC();
	const TInt count = args->Count();

#ifdef FEATURE_INSTALL_RESUME
	// If ADM is launched from the menu, we don't get any command line parameters
	// Need to read the info from the resume info file, if it exists.
	if (count == 1)
		{
		CleanupStack::PopAndDestroy(args);
		const TInt ret = ReadResumeInfoL();
		if (ret != KErrNone)
			{
			ShowGlobalNoteL(EAknGlobalErrorNote, R_ADM_ERR_NO_PENDING_INSTALLATIONS_TEXT);
			ExitApp();
			}
		iResumingInstallation = ETrue;
		return;
		}
#else
	if (count == 1)
		{
		User::Leave( KErrNotSupported );
		}
#endif // FEATURE_INSTALL_RESUME

	// index to the command line args, starting at 1 (0 = executable name)
	TInt index = 1;

#ifdef DO_LOG
	for (int i = 0; i < count; i++)
		{
		LOG3( "Arg[%d]='%S'", i, &(args->Arg(i)) );
		}
#endif

	TPtrC arg = args->Arg(index++);
	TLex lex(arg);
	TUint32 protocolVerRaw = 0;
	TUint32 protocolVer = 0;
	TUint32 tmp;
	if ( lex.Val(protocolVerRaw, EDecimal) == 0)
		{
		LOG3( "(cmd) pVer(raw) = %d (%03x)", protocolVerRaw, protocolVerRaw );
		protocolVer = (protocolVerRaw & KCmdLineBitProtocolVerMask);
		}
	else
		{
		LOG( "Invalid P/BVersion, PANIC" );
		Panic(EPanicAdmCmdLineArgs);
		}

	if (protocolVer < 15)
		{
		// assume it's old version without the bit field support
		LOG2( "Using old args %d", protocolVer );

		// Following are the command line args passed in the old version of Bootstrap:
		// arg 0 - ADM.exe
		// arg 1 - Bootstrap Version
		// arg 2 - WrapperUid
		// arg 3 - IAP
		// arg 4 - Sisfilename
		// arg 5 - Depfilename (optional)

		// Get the Bootstrap version
		iBootstrapVersion = protocolVer;
		LOG2("(cmd) BVersion: %x", iBootstrapVersion);

		// Get the Wrapper uid
		TPtrC uidPtr = args->Arg(index++);
		lex.Assign(uidPtr);
		TUint32 uid = 0;
		if ( lex.Val(uid, EDecimal ) == 0)
			{
			LOG2("(cmd) Wrapper Uid: 0x%x", uid);

			iWrapperPackageUid = TUid::Uid(uid);
			}

		// See if at least the minimum options required are provided
		if (count < 5)
			{
			LOG2( "Incorrect # of arguments (%d) passed from bootstrap, PANIC", count );
			Panic(EPanicAdmCmdLineArgs);
			}

		// Get Iap
		TPtrC iapPtr = args->Arg(index++);
		lex.Assign(iapPtr);
		if ( lex.Val(iIAP, EDecimal) == 0 )
			{
			LOG2("(cmd) IAP: %d", iIAP);
			iStateMachine->SetIAP(iIAP);
			}

		switch (iBootstrapVersion)
			{
			case 1:
			case 2:
				{
				if ( count != 6 )
					{
					LOG2( "Incorrect # of arguments (%d) passed from bootstrap, PANIC", count );
					Panic(EPanicAdmCmdLineArgs);
					}
				iDepFileName = args->Arg(index++).AllocL();
				LOG2( "(cmd) DepFile: '%S'", iDepFileName);

				iSisFileName = args->Arg(index++).AllocL();
				LOG2( "(cmd) AppSis: '%S'", iSisFileName);
				break;
				}
			case 3:
				{
				iDepFileName = args->Arg(index++).AllocL();
				LOG2( "(cmd) DepFile: '%S'", iDepFileName);
				break;
				}
			case 4:
				{
				iSisFileName = args->Arg(index++).AllocL();
				LOG2( "(cmd) AppSis: '%S'", iSisFileName);
				break;
				}
			default:
				LOG2( "Invalid BVersion %d, PANIC", iBootstrapVersion );
				Panic(EPanicAdmCmdLineArgs);
				break;
			}
		}
	else if (protocolVer == 15)
		{
		LOG( "Using new args" );

		// Command line arguments, version 15 specification:
		//
		//31               9  8  7  6  5  4  3  2  1  0
		// +-------------+--+--+--+--+--+--+--+--+--+--+
		// | reserved    |  |  |  |  |  |  |           |
		// +-------------+--+--+--+--+--+--+--+--+--+--+
		//
		//      value
		// bits range description
		//  0-3  0-15 Command line parameter protocol version:
		//             0 = not supported
		//             1 = ADM.exe 1 <wrapper_uid> <iap> <depfile> <sisfile>
		//             2 = ADM.exe 2 <wrapper_uid> <iap> <depfile> <sisfile>
		//             3 = ADM.exe 3 <wrapper_uid> <iap> <depfile>
		//             4 = ADM.exe 4 <wrapper_uid> <iap> <sisfile> (this was used in beta1, beta2)
		//            15 = ADM.exe 15 [parameters as specified by other bits]
		//
		//         since
		//  bit  version type command line parameter present
		//    4      4     N  Bootstrap version number
		//    5      4     N  Wrapper UID
		//    6      4     N  IAP
		//    7      4     N  ADM launch condition code:
		//                    KCmdLineCancelAdm: ADM needs to cancel installation
		//                    KCmdLineLaunchAdm: ADM starts normally
		//    8      4     S  Full path to dependency XML file
		//    9      4     S  Full path to application SIS file
		//
		// Types:
		//  N  Natural decimal number (range 0 - 2^32-1, fits to TUint32)
		//  S  UTF-8 string, must NOT contains spaces or other whitespaces
		//
		// Command line parameters appear in the order of the bits set, i.e.
		// if bits 4, 8, 9 are set the command line parameters are:
		// ADM.exe 784 <bootstrap_version> <dep_file> <sis_file>
		//
		// If command line protocol version is less than 15, it is assumed that
		// old version command line parameter format is used.
		//

		// new version. bit fields define which parameters are present
		// these has to be processed in the right order: from LSB to MSB
		if (protocolVerRaw & KCmdLineBitBootstrapVersion)
			{
			TPtrC arg = args->Arg(index++);
			lex.Assign(arg);
			if ( lex.Val(iBootstrapVersion) == 0 )
				{
				LOG2( "(cmd) BVersion: %x", iBootstrapVersion );
				}
			else
				{
				LOG( "Invalid BVersion" );
				Panic(EPanicAdmCmdInvalidBootstrap);
				}
			}
		if (protocolVerRaw & KCmdLineBitWrapperUid)
			{
			TPtrC arg = args->Arg(index++);
			lex.Assign(arg);
			if ( lex.Val(tmp, EDecimal) == 0 )
				{
				LOG2("(cmd) Wrapper Uid: 0x%x", tmp);
				iWrapperPackageUid = TUid::Uid(tmp);
				}
			else
				{
				LOG( "Invalid wrapper package UID" );
				Panic(EPanicAdmCmdInvalidWrapperUid);
				}
			}
		if (protocolVerRaw & KCmdLineBitIAP)
			{
			TPtrC arg = args->Arg(index++);
			lex.Assign(arg);
			if ( lex.Val(iIAP, EDecimal) == 0 )
				{
				LOG2("(cmd) IAP: %d", iIAP);
				iStateMachine->SetIAP(iIAP);
				}
			else
				{
				LOG( "Invalid IAP" );
				Panic(EPanicAdmCmdInvalidIAP);
				}
			}
		if (protocolVerRaw & KCmdLineBitADMLaunchControl)
			{
			TPtrC arg = args->Arg(index++);
			lex.Assign(arg);
			if ( lex.Val(tmp, EDecimal) == 0 )
				{
				LOG2("(cmd) LState %d", tmp);
				switch (tmp)
					{
				case KCmdLineLaunchAdm:
					// this is valid, nothing needs to be done
					break;
				case KCmdLineCancelAdmNoResume:
					iIsResumeRequired = EFalse;
					// fall-through
				case KCmdLineCancelAdm:
					iStateMachine->SetStartState(CStateFactory::EStatePrepareExitWithError);
					iStateMachine->SetFailureReason(EUserCancelled);
					break;
				default:
					LOG2( "Invalid LState %d, PANIC", tmp );
					Panic(EPanicAdmCmdInvalidLaunchState2);
					break;
					} // switch
				}
			else
				{
				LOG( "Invalid LState, PANIC" );
				Panic(EPanicAdmCmdInvalidLaunchState);
				}
			}
		if (protocolVerRaw & KCmdLineBitFileDep)
			{
			iDepFileName = args->Arg(index++).AllocL();
			LOG2( "(cmd) DepFile: '%S'", iDepFileName);
			}
		if (protocolVerRaw & KCmdLineBitFileSis)
			{
			iSisFileName = args->Arg(index++).AllocL();
			LOG2( "(cmd) SisFile: '%S'", iSisFileName);
			}
		}
	else
		{
		LOG2( "Invalid PVersion %d, PANIC", protocolVer );
		Panic(EPanicAdmCmdInvalidProtocol);
		}
	CleanupStack::PopAndDestroy(args);

	LOG3( "- ProcessCommandLineArgsL(): %d->%d", count, index );
	}

// -----------------------------------------------------------------------------
// Read the information from the resume info file, if launched from the menu.
// -----------------------------------------------------------------------------
//
TInt CADMAppUi::ReadResumeInfoL()
	{
	LOG( "+ ReadResumeInfo()" );
	RArray< TPtrC > lineBuffer;
	TInt err = 0;
	HBufC* buffer = ReadConfigFile( iRfs, KADMResumeInfoFile, lineBuffer, err );

	if ( buffer && err == KErrNone )
		{
		// Read the main application name
		TPtrC namePtr = GetConfigValue( KRFieldAppName, lineBuffer, err );
		if ( err == KErrNone )
			{
			iMainAppName = namePtr.AllocL();
			LOG2( "Resuming '%S'", iMainAppName );
			}

		// Get BootstrapVersion from the resume info file
		TPtrC bootstrapVersionLine = GetConfigValue( KRFieldBootstrap, lineBuffer, err );
		if ( err == KErrNone )
			{
			TLex lex(bootstrapVersionLine);
			if ( lex.Val(iBootstrapVersion) == 0 )
				{
				LOG2( "(resume) Version: %d", iBootstrapVersion );
				}
			else
				{
				// TODO: Error: Can this ever happen?!
				//LOG( "Incorrect version in the resume info" );
				return KErrNotSupported;
				}
			}
		else
			{
			LOG2( "Failed to read version from the resume info (%d)", err );
			return err;
			}
		}
	else
		{
		LOG( "! No resume information, cannot continue" );
		// Resume information file doesn't exist
		return err;
		}

	// Get the Wrapper uid
	TPtrC uidPtr = GetConfigValue( KRFieldWrapperPkgUid, lineBuffer, err );
	if ( err == KErrNone )
		{
		TLex lex(uidPtr);
		TUint32 uid = 0;
		if ( lex.Val(uid, EDecimal ) == 0)
			{
			LOG2( "Wrapper Uid: 0x%x", uid );
			iWrapperPackageUid = TUid::Uid(uid);
			}
		else
			{
			//LOG( "Incorrect wrapper UID in resume info" );
			return KErrNotSupported;
			}
		}
	else
		{
		LOG2( "Failed to read wrapper UID from the resume info (%d)", err );
		return err;
		}

	switch (iBootstrapVersion)
		{
		case 1:
		case 2:
		case 3:
			{
			// Get AppFileName from the resume information file
			TPtrC depFileNameLine = GetConfigValue( KRFieldDepFileName, lineBuffer, err );
			if ( err == KErrNone )
				{
				iDepFileName = depFileNameLine.AllocL();

				LOG2( "(resume) DepFileName = '%S'", iDepFileName );

				if ( !BaflUtils::FileExists(iRfs, *iDepFileName) )
					{
					LOG2( "(resume) DepFile '%S' missing, cannot continue!", iDepFileName );
					return KErrNotFound;
					}
				}
			else
				{
				LOG2( "Failed to read from the resume info (%d)", err );
				return err;
				}
			}
			break;
		case 4:
		default:
			break;
		}

	switch (iBootstrapVersion)
		{
		case 1:
		case 2:
		case 4:
			{
			// Get AppFileName from the resume info file
			TPtrC appFileNameLine = GetConfigValue( KRFieldAppFileName, lineBuffer, err );
			if ( err == KErrNone )
				{
				iSisFileName = appFileNameLine.AllocL();

				LOG2( "(resume) AppSis = '%S'", iSisFileName );

				if ( !BaflUtils::FileExists(iRfs, *iSisFileName) )
					{
					LOG2( "(resume) AppSis '%S' missing, cannot continue!", iSisFileName );
					return KErrNotFound;
					}
				}
			else
				{
				LOG2( "Failed to read from the resume info (%d)", err );
				return err;
				}
			}
			break;
		case 3:
		default:
			break;
		}
	LOG2( "- ReadResumeInfo(): ret=%d", err );
	return err;
	}

// -----------------------------------------------------------------------------
// Handles WindowServer events. Used to catch 'End Call' key.
// -----------------------------------------------------------------------------
//
void CADMAppUi::HandleWsEventL( const TWsEvent& aEvent, CCoeControl* aDestination )
	{
	if ( aEvent.Key()->iCode == EKeyPhoneEnd )
		{
		iStateMachine->HandleUserResponse( EKeyPhoneEnd );
		}
	else
		{
		CEikAppUi::HandleWsEventL( aEvent, aDestination );
		}
	}

// -----------------------------------------------------------------------------
// CADMAppUi::HandleCommandL()
// Takes care of command handling.
// -----------------------------------------------------------------------------
//
void CADMAppUi::HandleCommandL(TInt aCommand)
	{
	switch (aCommand)
		{
		case EEikCmdExit:
		case EAknSoftkeyExit:
			Exit();
			break;

		default:
			Panic(EPanicAdmUi);
			break;
		}
	}

// -----------------------------------------------------------------------------
// Callback CGlobalWaitNote
//
// Called when global wait note was cancelled
// -----------------------------------------------------------------------------
//
void CADMAppUi::WaitNoteCancelled()
	{
	LOG2( "! Wait note cancelled (%d)", iStateMachine->StateIndex() );
	iStateMachine->HandleUserResponse( EAknSoftkeyCancel );
	}

// -----------------------------------------------------------------------------
// Callback CProgressDialog
//
// Called when progress dialog was cancelled
// -----------------------------------------------------------------------------
//
void CADMAppUi::ProgressDialogCancelled()
	{
	LOG2( "! Progress dialog cancelled (%d)", iStateMachine->StateIndex() );
	iStateMachine->HandleUserResponse( EAknSoftkeyCancel );
	}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void CADMAppUi::HandleGlobalQueryResponseL(const TInt aResponse)
	{
	LOG2( "+ HandleGlobalQueryResponseL(): %d", aResponse );
	iStateMachine->HandleUserResponse( aResponse );
	}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void CADMAppUi::ShowDownloadQueryL(const TInt aResourceId, const TInt aInfoResourceId)
	{
	const TInt KMaxDownloadSizeMsg = 32;

	if ( iGlobalQueryObserver )
		{
		iGlobalQueryObserver->Cancel();
		delete iGlobalQueryObserver;
		iGlobalQueryObserver = NULL;
		}
	iGlobalQueryObserver = CGlobalQueryObserver::NewL(this, EFalse);

	DELETE_IF_NONNULL( iGlobalConfirmationQuery );
	DELETE_IF_NONNULL( iQueryMessage );
	iGlobalConfirmationQuery = CAknGlobalConfirmationQuery::NewL();

	TBuf<KMaxDownloadSizeMsg> dlSizeDescr;
	PrettyPrint( iStateMachine->TotalDownloadSize(), dlSizeDescr );

	CDesCArrayFlat* strings = new (ELeave) CDesCArrayFlat(3);
	CleanupStack::PushL(strings);
	HBufC* msg = StringLoader::LoadLC( R_ADM_SW_UPDATE_REQUIRED_TEXT, iEikonEnv );
	HBufC* info;
	if (aInfoResourceId != -1)
		{
		info = StringLoader::LoadLC( aInfoResourceId, iEikonEnv );
		}
	else
		{
		info = KNullDesC().AllocLC();
		}
	strings->AppendL(*msg);
	strings->AppendL(*info);
	strings->AppendL(dlSizeDescr);
	iQueryMessage = StringLoader::LoadL( aResourceId, *strings, iEikonEnv );
	CleanupStack::PopAndDestroy(3, strings); // strings, msg, info

	// Cancel the progress dialog just before querying the user to reduce flicker
	CancelProgressBar();

	iGlobalConfirmationQuery->ShowConfirmationQueryL(
		iGlobalQueryObserver->iStatus,
		*iQueryMessage,
		0
		);
	iGlobalQueryObserver->Start();
#if 0
	const TInt KMaxDownloadSizeMsg = 32;
	TBuf<KMaxDownloadSizeMsg> dlSizeDescr;
	PrettyPrint( iDepTree->GetTotalDownloadSize(), dlSizeDescr );
	HBufC* string = StringLoader::LoadLC( aResourceId, dlSizeDescr, iEikonEnv );

	CAknQueryDialog* dlg = CAknQueryDialog::NewL();
	const TInt ret = dlg->ExecuteLD( R_AVKON_DIALOG_EMPTY_MENUBAR, *string );

	CleanupStack::PopAndDestroy(); // string

	return ret;
#endif
	}

// -----------------------------------------------------------------------------
// Shows the application launch query dialog
// @param aAppName Application name, caption, to be shown to the user
// @param aIconFilename Full path to the application icon, KNullDesC if none.
// -----------------------------------------------------------------------------
//
void CADMAppUi::ShowLaunchPromptL(const TDesC& aAppName, const TDesC& aIconFilename)
	{
	if ( iGlobalQueryObserver )
		{
		iGlobalQueryObserver->Cancel();
		delete iGlobalQueryObserver;
		iGlobalQueryObserver = NULL;
		}
	iGlobalQueryObserver = CGlobalQueryObserver::NewL(this, EFalse);

	DELETE_IF_NONNULL( iGlobalConfirmationQuery );
	DELETE_IF_NONNULL( iQueryMessage );
	iGlobalConfirmationQuery = CAknGlobalConfirmationQuery::NewL();
	iQueryMessage = StringLoader::LoadL( R_ADM_LAUNCH_APP_TEXT, aAppName, iEikonEnv );
	iGlobalConfirmationQuery->ShowConfirmationQueryL(
		iGlobalQueryObserver->iStatus,
		*iQueryMessage,
		0, // Softkeys
		0, // Animation
		aIconFilename,
		EMbmAdmAdm,      // BitmapId
		EMbmAdmAdm_mask  // MaskId
		);
	iGlobalQueryObserver->Start();
	// Cancel the progress dialog and notes after creating the note to reduce flicker
	CancelProgressBar();
	CancelWaitNote();
	}

// -----------------------------------------------------------------------------
// @param aType Global note type.
// @param aResourceId Resource ID to text to be displayed.
// -----------------------------------------------------------------------------
//
TInt CADMAppUi::ShowGlobalNoteL( const TAknGlobalNoteType aType, const TInt aResourceId )
	{
	// Allocate TBuf with constant length.
	TBuf<KMaxMsgSize> text( NULL );

	// Do we have a valid resource ID for the note?
	if (aResourceId != -1)
		{
		// Reads a resource into a descriptor.
		iEikonEnv->ReadResourceL( text, aResourceId );

		if ( iStateMachine->FailedState() == CStateFactory::EStateLast &&
				iExitReason != EExitNoError)
			{
			const TInt error = iStateMachine->FailedState() * 100 + iExitReason;
			text.Append('\n');
			text.AppendNum( error );
			}

		// Cancel any progress dialog
		CancelProgressBar();
		// Cancel any wait notes
		CancelWaitNote();

		if (aType == EAknGlobalErrorNote )
			{
			CAknQueryDialog* dlg = CAknQueryDialog::NewL( CAknQueryDialog::EErrorTone );
			return dlg->ExecuteLD( R_ADM_EXIT_QUERY, text );
			}
		else
			{
			// Create new CAknGlobalNote instance.
			CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
			globalNote->ShowNoteL( aType, text );
			CleanupStack::PopAndDestroy(globalNote);
			}
		}
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// Shows the exit note with information, how the interrupted/cancelled installation
// can be continued.
// -----------------------------------------------------------------------------
//
TInt CADMAppUi::ShowExitNoteL()
	{
	TInt ret = KErrNone;
	// The order of this table must match TExitReason order
	static const TInt errorNotes[ELastExitState] = {
/* EExitNoError           0 */  -1,
/* EUserCancelled         1 */  -1, //R_ADM_INST_CAN_BE_RESUMED_TEXT,
/* EDownloadFailed        2 */  R_ADM_ERR_DOWNLOAD_FAILED_TEXT,
/* EInsufficientMemory    3 */  R_ADM_ERR_INSTALLATION_NOT_ENOUGH_SPACE_TEXT,
/* EDeviceNotSupported    4 */  R_ADM_ERR_INSTALLATION_UNSUPPORTED_DEVICE_TEXT,
/* EInstallationFailed    5 */  R_ADM_ERR_INSTALLATION_FAILED_TEXT,
/* ERootInstallationFailed  */  -1
	};

	// First, show an error note describing what went wrong
	if (errorNotes[iExitReason] > 0)
		{
		CAknErrorNote* note = new (ELeave) CAknErrorNote( ETrue );
		HBufC* msg = StringLoader::LoadLC( errorNotes[iExitReason], iEikonEnv );
		note->ExecuteLD( *msg );
		CleanupStack::PopAndDestroy(); // msg
		}

	if (iExitReason != EDeviceNotSupported)
		{
		// Then show the "installation can be continued later" information
		// but only if the device is a supported one.
		CAknQueryDialog* dlg = CAknQueryDialog::NewL( CAknQueryDialog::EErrorTone );
		HBufC* oviMsg = NULL;
		if (iOviStoreRunning)
			{
			// TODO: Change ADM so root node would always contain the main application sis information
			HBufC* caption = iStateMachine->LaunchCaption();
			if (!caption)
				{
				caption = KNullDesC().AllocL();
				}
			oviMsg = StringLoader::LoadLC(
					R_ADM_INST_CAN_BE_RESUMED_OVI_TEXT,
					*caption,
					iEikonEnv
					);
			}
		else
			{
			oviMsg = KNullDesC().AllocLC();
			}
		HBufC* mainMsg = StringLoader::LoadLC(
				R_ADM_INST_CAN_BE_RESUMED_TEXT,
				*oviMsg,
				iEikonEnv
				);
		ret = dlg->ExecuteLD( R_ADM_EXIT_QUERY, *mainMsg );
		CleanupStack::PopAndDestroy(2, oviMsg);
		}
	return ret;
	}

// -----------------------------------------------------------------------------
// Creates a wait note displaying given resource ID.
// @param aResourceId Resource ID to be shown
// @param aCancellable ETrue, if wait note is cancellable
// @param aDetailedResourceId Additional resource ID to be shown, -1 if none
// -----------------------------------------------------------------------------
//
void CADMAppUi::ShowWaitNoteL( const TInt aResourceId,
		const TBool aCancellable,
		const TInt aDetailedResourceId
		)
	{
	TBuf<KMaxMsgSize> resourceMsg;
	CancelWaitNote();

	if (aDetailedResourceId != -1)
		{
		iEikonEnv->ReadResourceL( resourceMsg, aDetailedResourceId );
		HBufC* msg = StringLoader::LoadL( aResourceId, resourceMsg, iEikonEnv );
		resourceMsg.Copy( *msg );
		delete msg;
		}
	else
		{
		iEikonEnv->ReadResourceL( resourceMsg, aResourceId );
		}

	iWaitNote = CGlobalWaitNote::NewL(*this, aCancellable );
	iWaitNote->ShowNoteL( resourceMsg );
	}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void CADMAppUi::ShowWaitNoteNumL( const TInt aResourceId, const TInt aCurrent, const TInt aLast)
	{
	CancelWaitNote();

	CArrayFix<TInt>* vals = new (ELeave) CArrayFixFlat<TInt>(2);
	CleanupStack::PushL(vals);
	vals->AppendL(aCurrent);
	vals->AppendL(aLast);
	HBufC* msg = StringLoader::LoadLC( aResourceId, *vals, iEikonEnv );

	iWaitNote = CGlobalWaitNote::NewL( *this, ETrue );
	iWaitNote->ShowNoteL( *msg );

	CleanupStack::PopAndDestroy(2, vals);
	}

// -----------------------------------------------------------------------------
// Removes currently shown wait note.
// -----------------------------------------------------------------------------//
//
void CADMAppUi::CancelWaitNote()
	{
	if ( iWaitNote )
		{
		TRAP_IGNORE( iWaitNote->CancelNoteL() );
		delete iWaitNote;
		iWaitNote = NULL;
		}
	}

// -----------------------------------------------------------------------------
// Removes currently shown progress bar.
// -----------------------------------------------------------------------------//
//
void CADMAppUi::CancelProgressBar()
	{
	if ( iProgress )
		{
		iProgress->Cancel();
		}
	}

// -----------------------------------------------------------------------------
// ShowGlobalProgressL()
//
// aResourceId  Resource ID of the text to be shown on the progress bar
// aStartValue  Progress bar start value
// aEndValue    Progress bar end value
// aCurrent     Resource string value0
// aLast        Resource string value1
// -----------------------------------------------------------------------------
//
void CADMAppUi::ShowGlobalProgressL(const TInt aResourceId,
		const TInt aStartValue, const TInt aEndValue,
		const TInt aCurrent, const TInt aLast)
	{
	HBufC *msg = NULL;
	CArrayFix<TInt>* vals = new (ELeave) CArrayFixFlat<TInt>(2);
	CleanupStack::PushL(vals);

	if (aCurrent != -1)
		{
		vals->AppendL(aCurrent);
		vals->AppendL(aLast);

		// Read the resource
		msg = StringLoader::LoadLC( aResourceId, *vals, iEikonEnv );
		}
	else
		{
		// Read the resource
		msg = iEikonEnv->AllocReadResourceLC( aResourceId );

		// Special case: append the application name to the string
		if (aResourceId == R_ADM_CONTINUING_INST_TEXT)
			{
			if (iMainAppName && iMainAppName->Length() > 0)
				{
				HBufC* newmsg = HBufC::NewL(msg->Length() + iMainAppName->Length() + 3);
				newmsg->Des().Copy(*msg);
				newmsg->Des().Append('\n');
				newmsg->Des().Append('\'');
				newmsg->Des().Append(*iMainAppName);
				newmsg->Des().Append('\'');
				CleanupStack::PopAndDestroy(msg);
				msg = newmsg;
				CleanupStack::PushL(msg);
				}
			}
		}

	iProgress->Cancel();
	iProgress->StartL( *msg, aEndValue );
	iProgress->Update(aStartValue, aEndValue);

	CleanupStack::PopAndDestroy(2, vals); // msg, vals
	}

// -----------------------------------------------------------------------------
// Shows a proper wait note before the cleanup starts.
//
// This function MUST NOT LEAVE.
// -----------------------------------------------------------------------------
//
void CADMAppUi::HandleFailure()
	{
	LOG3( "+ CADMAppUi::HandleFailure(): %d. err=%d", iStateMachine->StateIndex(), iExitReason);
	// Disable wait note and progress bar, if any
	CancelProgressBar();
	CancelWaitNote();

	// Delete the dep file
	if ( iDepFileName )
		{
		// We need to ignore, if delete leaves as we are currently already
		// handling an error case.
		// TODO: Remove if(), DeleteFile() copes with NULL filenames.
		DeleteFile( *iDepFileName );
		// TODO: Should we 'delete iDepFileName;' and set it to NULL?
		}
	TInt err = KErrNone;
	TInt waitNoteResource;
	TInt detailedInfoResource = -1;

	switch (iExitReason)
		{
		case EDownloadFailed:
			waitNoteResource = R_ADM_DETAILED_CANCELLING_INSTALLATION_WAIT_TEXT;
			detailedInfoResource = R_ADM_ERR_CONN_LOST_TEXT;
			break;
		case EUserCancelled:
		case EInstallationFailed:
			waitNoteResource = R_ADM_CANCELLING_INSTALLATION_WAIT_TEXT;
			break;
		default:
			waitNoteResource = R_ADM_REVERTING_CHANGES_WAIT_TEXT;
			break;
		}

	// Do the cleanup depending on the state that experienced failure
	if ( iStateMachine->FailedState() >= CStateFactory::EStateDownloadChangesFile )
		{
		TRAP(err, ShowWaitNoteL( waitNoteResource, EFalse, detailedInfoResource ));
		}

	LOG2( "- CADMAppUi::HandleFailure(): %d", err );
	}

// -----------------------------------------------------------------------------
// Shows the final error message and exits application
// -----------------------------------------------------------------------------
//
void CADMAppUi::ExitApp()
	{
	LOG3( "+ CADMAppUi::ExitApp(): %d, %d", iExitReason, iAppLaunch );

	// Remove any progress bar
	CancelProgressBar();
	// Remove any wait note
	CancelWaitNote();

	// Just checking that iExitReason is in the proper range
	if ( iExitReason >= 0 && iExitReason < ELastExitState )
		{
		// If we have an additional note to display, show it. We need to
		// trap any leaves.
		TRAP_IGNORE(
				{
				if ( iSilentInstallationOk && iExitReason == EExitNoError )
					{
					// If we used non-silent installation, the "Installation complete" note
					// was already shown by S60 Installer. Don't show it here again.
					// If the user has launched the application, don't show the note
					if (!iNonSilentInstallation && !iAppLaunch)
						{
						ShowGlobalNoteL( EAknGlobalConfirmationNote, R_ADM_INSTALLATION_OK_TEXT );
						// We need to wait 350ms to show the note as the call to Exit() below would kill
						// the AppUi and also the note.
						User::After(350000);
						}
					}
				else
					{
					if (!iNonSilentInstallation)
						{
						// Show ADM again in task list. This is because we're using
						// CAknQueryDialog: we don't want that to get hidden.
						HideApplicationFromFSW(EFalse);
						// This call returns after user has dismissed the error dialog
						ShowExitNoteL();
						}
					}
				}
			);
		}
#ifdef _DEBUG
	else
		{
		LOG2( "Invalid exit reason %d", iExitReason );
		User::Invariant();
		}
#endif

	// Set the ADM icon hidden, if everything went smoothly or any resume info file exists.
	const TBool hideAdm = !( (iExitReason != EExitNoError || iExitReason == EDeviceNotSupported) && iIsResumeRequired );
	const TInt err = CUtils::HideApplicationFromMenu( KUidADMApp.iUid, hideAdm );
	LOG3( "ADM icon hidden: %d (%d)", hideAdm, err );

	RunAppShutter();
	Exit();

	LOG( "- CADMAppUi::ExitApp()" );
	}

// -----------------------------------------------------------------------------
// Delete a file pointed by aFilename.
// -----------------------------------------------------------------------------
//
void CADMAppUi::DeleteFile(const TDesC& aFilename)
	{
	iRfs.Delete(aFilename);
	}

// -----------------------------------------------------------------------------
// Pretty prints number as text string using KiB, MiB and GiB prefixes when needed.
//
// aSize    Number to pretty print. Only positive integers supported.
// aDescr   Descriptor holding the pretty printed number string.
// -----------------------------------------------------------------------------
//
void CADMAppUi::PrettyPrint(const TUint32 aSize, TDes& aDescr)
	{
	_LIT(KFmtDecimals,  "%02d");
	TLocale locale;
	TUint32 size = aSize, rem;
	TPtrC sizePrefix( iPrefixKb );

	// We don't pretty print bytes because "bytes" would a new string
	// to localize. This is just to minimize that work.
	if (aSize < 1024*1024)
		{
		size /= 1024;
		rem = (aSize * 100 / 1024) % 100;
		}
	else if (aSize < 1024*1024*1024)
		{
		size /= 1024*1024;
		rem = (aSize * 100 / (1024*1024)) % 100;
		sizePrefix.Set( iPrefixMb );
		}
	else
		{
		// TInt64 is needed, because aSize*100 will overflow on big values of aSize
		TInt64 remBig( aSize );
		remBig = ((remBig * 100) / (1024*1024*1024)) % 100;
		rem = remBig;
		size /= 1024*1024*1024;
		sizePrefix.Set( iPrefixGb );
		}

	aDescr.Num(size);
	// Add decimals only if they != .00
	if (rem)
		{
		aDescr.Append(locale.DecimalSeparator());
		aDescr.AppendFormat(KFmtDecimals, rem);
		}
//    if (aSize > 999)
//        aDescr.Insert(aDescr.Length() - 6, iLocale.ThousandsSeparator());
	aDescr.Append(sizePrefix);
}

// -----------------------------------------------------------------------------
// Gets detailed phone information and stores it internally.
//
// Returns KErrNone, if fetching of machine UID was succesful
// -----------------------------------------------------------------------------
//
TInt CADMAppUi::GetPhoneInformation()
	{
	LOG( "+ GetPhoneInformation()" );

	//TODO: Remove unnecessary information, currently MachineUid is only needed
	TInt r = HAL::Get(HALData::EMachineUid, iMachineUid);
#if _DEBUG
	HAL::Get(HALData::EManufacturer, iManufacturer);
	HAL::Get(HALData::EManufacturerHardwareRev, iHardwareRev);
	HAL::Get(HALData::EManufacturerSoftwareRev, iSoftwareRev);
	HAL::Get(HALData::EModel, iModel);
	HAL::Get(HALData::EDeviceFamily, iDeviceFamily);
	HAL::Get(HALData::EDeviceFamilyRev, iDeviceFamilyRev);
	HAL::Get(HALData::ECPUArch, iCpuArch);
	HAL::Get(HALData::ECPUABI, iCpuABI );
	HAL::Get(HALData::ECPUSpeed, iCpuSpeed );
#endif
	TPtr swVer(iSwVersion->Des());
	SysUtil::GetSWVersion(swVer);

	LOG8_2( "  machine uid = 0x%08x",       iMachineUid);
#if _DEBUG
	LOG8_2( "  model = 0x%08x",             iModel);
	LOG8_2(	"  manufacturer	= %d",			iManufacturer);
	LOG8_2(	"  hardware	rev	= %d",			iHardwareRev);
	LOG8_2(	"  software	rev	= %d",			iSoftwareRev);
	LOG8_2(	"  device family = %d",			iDeviceFamily);
	LOG8_2(	"  device family rev = %d",		iDeviceFamilyRev);
	LOG8_2(	"  CPU architecture	= 0x%08x",	iCpuArch);
	LOG8_2(	"  CPU ABI = %d",				iCpuABI);
	LOG8_2(	"  CPU speed = %d",				iCpuSpeed);
#endif
	LOG2("	Sw Ver = %S",					iSwVersion);

	LOG8_2( "- GetPhoneInformation (%d)", r);

	return r;
	}

// -----------------------------------------------------------------------------
// Returns true if the phone is roaming
// -----------------------------------------------------------------------------
//
TBool CADMAppUi::RegisteredRoaming()
	{
	LOG( "+ RegisteredRoaming()" );
	// Get registeration status
	TRequestStatus status;
	TInt ret = EFalse; // Default to not roaming

	RMobilePhone::TMobilePhoneRegistrationStatus regStatus(
		RMobilePhone::ERegistrationUnknown );
	iPhone.GetNetworkRegistrationStatus( status, regStatus );
	User::WaitForRequest( status );

	if ( RMobilePhone::ERegisteredRoaming == regStatus )
		{
		ret = ETrue;
		}

	LOG2( "- RegisteredRoaming: %d", ret );

	return ret;
	}
#if 0
// ---------------------------------------------------------------------------
// CADMAppUi::PhoneMemoryDrive
//
// @return Drive number for phone memory.
// ---------------------------------------------------------------------------
//
TInt CADMAppUi::PhoneMemoryDrive()
	{
	TInt res = 0;
	TInt err = RFs::CharToDrive( PathInfo::PhoneMemoryRootPath()[0], res );
	__ASSERT_ALWAYS( !err, Panic( EPanicAdmFileSystemAccess ) );

	return res;
	}

// ---------------------------------------------------------------------------
// CADMAppUi::MemoryCardDrive
//
// @return Drive number for memory card.
// ---------------------------------------------------------------------------
//
TInt CADMAppUi::MemoryCardDrive()
	{
	TInt res = 0;
	TInt err = RFs::CharToDrive( PathInfo::MemoryCardRootPath()[0], res );
	__ASSERT_ALWAYS( !err, Panic( EPanicAdmFileSystemAccess ) );

	return res;
	}
#endif
// ---------------------------------------------------------------------------
// CADMAppUi::ReadStaticResourcesL
//
// @return KErrNone if configuration was read correctly, error code otherwise
// ---------------------------------------------------------------------------
//
void CADMAppUi::ReadStaticResourcesL()
	{
	iEikonEnv->ReadResourceL( iPrefixKb, R_KB );
	iEikonEnv->ReadResourceL( iPrefixMb, R_MB );
	iEikonEnv->ReadResourceL( iPrefixGb, R_GB );
	}

// ---------------------------------------------------------------------------
// CADMAppUi::UsingWLAN
//
// @return ETrue, if selected bearer is WLAN
// ---------------------------------------------------------------------------
//
TBool CADMAppUi::UsingWLAN()
	{
	return BearerType() == EBearerWLAN;
	}

// ---------------------------------------------------------------------------
// CADMAppUi::CheckBearerTypeL
//
// @return Bearer type
// ---------------------------------------------------------------------------
//
TInt CADMAppUi::BearerType()
	{
	LOG2( "+ BearerType(): IAP=%d", iIAP );
	RConnectionMonitor monitor;
	TRequestStatus status = KRequestPending;
	TUint iapId(0);
	TInt bearer( 0 );
	TUint count;
	TUint ids[ 15 ];

	TRAPD( err, monitor.ConnectL() );
	if (err != KErrNone )
		{
		LOG2( "BearerType: Connect to RConnMon failed. %d", err );
		return err;
		}

	// Get the connection count
	monitor.GetConnectionCount( count, status );
	User::WaitForRequest( status );
	if ( status.Int() != KErrNone )
		{
		LOG2( "GetConnCount failed. %d", status.Int() );
		monitor.Close();
		return status.Int();
		}
#ifdef DO_LOG
	else
		{
		LOG2( "BearerType: %d connections:", count);
		}
#endif

	// Get the connection info for each connection
	TUint numSubConnections;
	TInt i;

	for ( i = 1; i <= count; i++ )
		{
		TInt ret = monitor.GetConnectionInfo( i, ids[ i-1 ], numSubConnections );
		if ( ret == KErrNone )
			{
			LOG3( "BearerType: ConnID[%d] = %d" , i, ids[ i-1 ] );
			// Get the IAP Id of the connection
			monitor.GetUintAttribute( ids[ i-1 ], 0, KIAPId, iapId, status );
			User::WaitForRequest( status );
			if ( status.Int() != KErrNone )
				{
				LOG2( "GetIapId failed. %d", status.Int() );
				// try next connection
				continue;
				}
#ifdef DO_LOG
			else
				{
				LOG3( "BearerType: IapId = %d, IAP = %d", iapId, iIAP );
				}
#endif
			// If the IAP matches with the one set in ADM
			// iIAP is initialized to KInvalidIapId
			if ( iapId == iIAP || iIAP == KInvalidIapId )
				{
#ifdef DO_LOG
				LOG2( "BearerType: Getting bearer for IapId %d", iapId );
#endif
				// Get the Bearer of the IAP Id.
				monitor.GetIntAttribute( ids[ i-1 ], 0, KBearer, bearer, status );
				User::WaitForRequest( status );
				if ( status.Int() != KErrNone )
					{
					LOG2( "BearerType: GetBearerType failed. %d", status.Int() );
					// try next connection
					continue;
					}
#ifdef DO_LOG
				else
					{
					LOG3( "BearerType: IapId %d: bearer = %d", iapId, bearer );
					}
#endif
				// we found matching IAP ID, break out of the loop
				break;
				}
			}
		else
			{
			LOG2( "GetConnInfo failed. %d", ret );
			return ret;
			}
		}
	TBuf<KConnMonMaxStringAttributeLength> iapName;

	// Get the string attrib of the IAP Id
	monitor.GetStringAttribute( ids[ i-1 ], 0, KIAPName, iapName, status );
	User::WaitForRequest( status );
	if ( status.Int() != KErrNone )
		{
		LOG2( "BearerType: GetStrAttr failed. %d", status.Int() );
		}
	else
		{
		LOG5( "* Selected IAP %d (%d), conn %d '%S'", iapId, bearer, ids[i-1], &iapName );
		}

	// Close the RConnMon object
	monitor.Close();

	LOG2( "- BearerType(): %d", bearer );

	return bearer;
	}

// ---------------------------------------------------------------------------
// CADMAppUi::ReadConfiguration
//
// @return KErrNone if configuration was read correctly, error code otherwise
// ---------------------------------------------------------------------------
//
TInt CADMAppUi::ReadConfigurationL()
	{
	TFileName configFile;
	RArray< TPtrC > lineBuffer;
	TInt ret( KErrNone );

	// Find the configuration file from the private directory
	ret = iRfs.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(iRfs, configFile, lineBuffer, ret );

		if ( buffer && ret == KErrNone )
			{
			TPtrC line = GetConfigValue( KCfgTagUrl, lineBuffer, ret );
			if ( ret == KErrNone )
				{
				iConfigUrl = HBufC8::NewL(line.Length());
				iConfigUrl->Des().Copy(line);
				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;
	}

// End of File