locationcentre/lcutils/src/lcapplauncher.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:16:03 +0200
changeset 0 522cd55cc3d7
child 9 91123d004e8f
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2007 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:  Utility class which provides the Application, Service and File
*                launching services to Location Centre.
*
*/


// SYSTEM INCLUDES
#include <apgcli.h>
#include <apgtask.h>
#include <eikenv.h>
#include <lcappexitobserver.h>
#include <SchemeHandler.h>
#include <documenthandler.h>
#include <e32math.h>
#include <eikappui.h>
#include <avkon.hrh>

// USER INCLUDES
#include "lcapplauncher.h"
#include "lcipcparams.h"
#include "lcdebug.h"

// CONSTANT DEFINITIONS
_LIT( KLcFourSpace, "4 " );

// Maximum value that the UID field can take in S60
const TUint32   KUidMaxValue = 0xFFFFFFFF;

// Application Server Service ID. This is the same valuw which AknAppService classes use
const TUid KLcLaunchAppServiceUid = { 0x101F887A };

// -------- Member functions of RLcLaunchAppService --------------------------

// ---------------------------------------------------------
// TUid RLcLaunchAppService::ServiceUid
// ---------------------------------------------------------
//
TUid RLcLaunchAppService::ServiceUid() const
    {
    return KLcLaunchAppServiceUid;
    }

// -------- Member functions of CLcLaunchAppService --------------------------

// ---------------------------------------------------------------------------
// CLcLaunchAppService* CLcLaunchAppService::NewL
// ---------------------------------------------------------------------------
//
CLcLaunchAppService* CLcLaunchAppService::NewL()
	{
	CLcLaunchAppService* self = new ( ELeave ) CLcLaunchAppService();
	return self;
	}

// ---------------------------------------------------------------------------
// CLcLaunchAppService::~CLcLaunchAppService
// ---------------------------------------------------------------------------
//		
CLcLaunchAppService::~CLcLaunchAppService()
	{
    delete iMonitor;
    iService.Close();	
	}

// ---------------------------------------------------------------------------
// Tvoid CLcLaunchAppService::ServerName
// ---------------------------------------------------------------------------
//
void CLcLaunchAppService::ServerName( TName& 	aServerName,
					 				  TUid 		aAppServerUid,
					 				  TUint 	aServerDifferentiator )
	{
	_LIT(KServerNameFormat, "%08x_%08x_AppServer");
	aServerName.Format( KServerNameFormat, 
						aServerDifferentiator, 
						aAppServerUid );
	}

// ---------------------------------------------------------------------------
// TUid RLcLaunchAppService::ServiceUid
// ---------------------------------------------------------------------------
//	
TUint CLcLaunchAppService::GenerateServerDifferentiatorAndName( 
										TName& 		aServerName, 
										TUid 		aAppServerUid )
	{
	TUint r;
	FOREVER
		{
		r = Math::Random();
		if ( r == 0 )
			continue;
		ServerName( aServerName, aAppServerUid, r );
		TFindServer find( aServerName );
		TFullName fullName;
		if ( find.Next( fullName ) == KErrNone )
			{
			continue;
			}			
		break;
		}		
	return r;
	}

// ---------------------------------------------------------------------------
// void CLcLaunchAppService::LaunchAppL
// ---------------------------------------------------------------------------
//		
void CLcLaunchAppService::LaunchAppL( const TUid& 						aAppUid, 
    					   				    MAknServerAppExitObserver& 	aObserver, 
    				 				  const TDesC&               		aCmdLineArg )
	{	
	DEBUG("+ CLcLaunchAppService::LaunchAppL")
		
	CEikonEnv* eikEnv = CEikonEnv::Static();		
	RWindowGroup& wg = eikEnv->RootWin();
	
	TName notUsed;
	const TUint differentiator = GenerateServerDifferentiatorAndName( notUsed, aAppUid );
	TRequestStatus requestStatusForRendezvous;
	
	RApaLsSession apa;
	User::LeaveIfError( apa.Connect());
	CleanupClosePushL( apa );
	
    // Check for the Application capabilities
    TApaAppCapabilityBuf capabilityBuf;
    User::LeaveIfError( apa.GetAppCapability( capabilityBuf, aAppUid ));
    TApaAppCapability& caps = capabilityBuf();
	
	// Launch only those applications can be embedded and will not be run the background
	
	if( caps.iLaunchInBackground || 
	    caps.iEmbeddability == TApaAppCapability::ENotEmbeddable )
		{
		User::Leave( KErrNotSupported );
		}
			
	TApaAppInfo info;
	User::LeaveIfError( apa.GetAppInfo( info, aAppUid ));

    // Pack the command line arguments
	CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
	cmdLine->SetExecutableNameL(info.iFullName);
	cmdLine->SetServerRequiredL(differentiator);

    // Set the Command line arguments.
    if ( aCmdLineArg.Length())
        {
        // These arguments would be sent as Tail end arguments to the launched
        // Application. Its left to the application to handle those
        HBufC8* tailEnd = HBufC8::NewLC( aCmdLineArg.Length());
        tailEnd->Des().Copy( aCmdLineArg );
        
        // The Tail end buffer is copied to the Command line structure. Hence,
        // can delete this variable after the set operation succeeds.
        cmdLine->SetTailEndL( tailEnd->Des());
        
        CleanupStack::PopAndDestroy( tailEnd );
        }

	cmdLine->SetCommandL( EApaCommandRun );

	// Window chain the client with the current application
	const TInt parentWindowGroupID = wg.Identifier();
	if ( parentWindowGroupID )
		{
		cmdLine->SetParentWindowGroupID( parentWindowGroupID );
		wg.AllowProcessToCreateChildWindowGroups( aAppUid );
		}

	// Launch the requested Application
	TThreadId threadNotUsed;
	User::LeaveIfError( apa.StartApp( *cmdLine, 
								      threadNotUsed, 
								      &requestStatusForRendezvous ));

	CleanupStack::PopAndDestroy(2, &apa);	// cmdLine and apa	
	
	CEikAppUi* appUi = eikEnv->EikAppUi();
	if ( appUi )
		{
		appUi->DeactivateActiveViewL();
		}

	User::WaitForRequest( requestStatusForRendezvous );
	User::LeaveIfError( requestStatusForRendezvous.Int());
	
	// Establish a connection to the running server
	TName serverName;
	ServerName( serverName, aAppUid, differentiator );
	
	// Though the server had been successfully created the application
	// has can shutdown before we can establish a connection. There is nothing
	// that we can do here. Ignore the error.	
	iService.ConnectExistingByNameL(serverName );

	// Set the observer for receiving notifications of the application exit.
    iMonitor = CApaServerAppExitMonitor::NewL( iService, 
    										   aObserver,
    										   CActive::EPriorityStandard );
    										   
    DEBUG("- CLcLaunchAppService::LaunchAppL")    										   
	}
    				 

// ----- Member funtions for CLcAppLauncher ----------------------------------

// ---------------------------------------------------------------------------
// CLcAppLauncher::CLcAppLauncher
// ---------------------------------------------------------------------------
//
CLcAppLauncher::CLcAppLauncher()
    {
    // C++ Default constructor. No allocations or functions which can Leave
    // should be called from here.
    }
         
// ---------------------------------------------------------------------------
// CLcAppLauncher::~CLcAppLauncher
// ---------------------------------------------------------------------------
//
CLcAppLauncher::~CLcAppLauncher()
    {
	
	// Delete the Broswer launcher.
	delete iBrowserLauncher;
	
	// Delete the document handler.
	delete iDocHandler;
	
	// Delete the Application Service if it exists
	delete iAppService;    	
    }
        
// ---------------------------------------------------------------------------
// CLcAppLauncher* CLcAppLauncher::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C CLcAppLauncher* CLcAppLauncher::NewL()
    {
    CLcAppLauncher* self = NewLC();
    CleanupStack::Pop( self );
    return self;         
    }

// ---------------------------------------------------------------------------
// CLcAppLauncher* CLcAppLauncher::NewLC
// ---------------------------------------------------------------------------
//
EXPORT_C CLcAppLauncher* CLcAppLauncher::NewLC()
    {
    // Symbian Two phased constructor. Leaves the object on the Clean-up
    // stack.
    CLcAppLauncher* self = new ( ELeave ) CLcAppLauncher();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;         
    }

// ---------------------------------------------------------------------------
// void CLcAppLauncher::ConstructL
// ---------------------------------------------------------------------------
//
void CLcAppLauncher::ConstructL()
    {
    // Second phase of the two phase constructor.    
    iEnv = CEikonEnv::Static();
    }

// ---------------------------------------------------------------------------
// void LcAppLauncher::LaunchLocationApplicationL
// ---------------------------------------------------------------------------
//
EXPORT_C void CLcAppLauncher::LaunchLocationApplicationL(
                                TInt                 	aAppType,
                          const TDesC&                  aIdentifer,
                                TBool                   aStandAlone,
                          const TDesC&                  aCmdLineArg,
                                MLcAppExitObserver*     aExitObserver )
    {  
    DEBUG("+ CLcLaunchAppService::LaunchLocationApplicationL")
    
    // Check for the validity of the request
    
    // Check if there is an outstanding Embedded launch request
    if(( isEmbeddedLaunchOutstanding && !aStandAlone ) ||
       ( !aStandAlone && !iEnv ))
    	{
        User::Leave( KErrNotSupported );    	
    	}
    
    // At any instant of time this class can one outstanding Exit observer.
    // There is currently no provision of storing a list of observers and
    // mapping them correspondingly to each of the assciated applications
    // Hence, Leave if there exists an Exit observer.
    if (( aExitObserver && iExitObserver ))
        {
        User::Leave( KErrAlreadyExists );
        }
        
    // Launch the Applications based on their type and Mode of launching
    switch ( aAppType )
        {
        case ELcNativeApplication:
            {
            // Since the request is for a Native S60 application, the Identifer
            // contains an UID. Obtain it using Lexer
            TLex lexer( aIdentifer );
            TUint32 uidValue;
            
            User::LeaveIfError( lexer.BoundedVal( uidValue, EHex, KUidMaxValue ));
            
            if ( aStandAlone )
            	{
	            // Launch the Location based Application based standalone mode
	            LaunchAppL( TUid::Uid( uidValue ), aCmdLineArg );   	
            	}
			else
				{
				// Launch Application in the chained mode
				LaunchAppAsChainedL( TUid::Uid( uidValue ), aCmdLineArg, aExitObserver );
				}
                
            break;
            }
        case ELcWebUrl:
            {
            LaunchWebBroserL( aIdentifer, aStandAlone, aExitObserver );
            break;
            }
        case ELcDocument:
            {
            LaunchContentL( aIdentifer, aStandAlone, aExitObserver );
            break;
            }
        default:
            {
            User::Leave( KErrNotSupported );
            break;
            }
        }
        
    DEBUG("+ CLcLaunchAppService::LaunchLocationApplicationL")        
    }
        
// ---------------------------------------------------------------------------
// void LcAppLauncher::LaunchAppL
// ---------------------------------------------------------------------------
//
void CLcAppLauncher::LaunchAppL(
                                TUid                    aApplicationUid,
                          const TDesC&                  aCmdLineArg )
    {  
    DEBUG("+ CLcAppLauncher::LaunchAppL")
    
    // Create the Session handle and connect to the Application architecture
    // server. This is required to obtain the details of the application from
    // the Application UID.
    RApaLsSession lsSession;
    User::LeaveIfError( lsSession.Connect() );
    CleanupClosePushL( lsSession );
        
    // Get the Application's capability.
    TApaAppCapabilityBuf capabilityBuf;
    User::LeaveIfError( lsSession.GetAppCapability( capabilityBuf, aApplicationUid ));
    TApaAppCapability& caps = capabilityBuf();
	
	if ( caps.iEmbeddability == TApaAppCapability::EEmbeddableOnly ||
	     caps.iEmbeddability == TApaAppCapability::EEmbeddableUiNotStandAlone )
	    {
	    User::Leave( KErrNotSupported );
	    }
		            
    // Get the Application Information.
    TApaAppInfo appInfo;    
    User::LeaveIfError( lsSession.GetAppInfo( appInfo, aApplicationUid ) );
    
    // Fill the command line argument structure
    CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
    
    // Set the Application name.    
    TFileName appName = appInfo.iFullName;
    cmdLine->SetExecutableNameL( appName );
    
    // Set the Command
    if ( caps.iLaunchInBackground )
        {
        cmdLine->SetCommandL( EApaCommandBackground );
        }
    else
        {
        cmdLine->SetCommandL( EApaCommandRun );
        }

    // Set the Command line arguments.
    if ( aCmdLineArg.Length())
        {
        // These arguments would be sent as Tail end arguments to the launched
        // Application. Its left to the application to handle those
        HBufC8* tailEnd = HBufC8::NewLC( aCmdLineArg.Length());
        tailEnd->Des().Copy( aCmdLineArg );
        
        // The Tail end buffer is copied to the Command line structure. Hence,
        // can delete this variable after the set operation succeeds.
        cmdLine->SetTailEndL( tailEnd->Des());
        
        CleanupStack::PopAndDestroy( tailEnd );
        }

	// Start the Application
	User::LeaveIfError( lsSession.StartApp( *cmdLine ));
    
    // Clean up all the allocated heap variables.
    CleanupStack::PopAndDestroy( cmdLine );
    CleanupStack::PopAndDestroy(); //lsSession 		         
    
    DEBUG("- CLcAppLauncher::LaunchAppL")
    }

// ---------------------------------------------------------------------------
// void LcAppLauncher::LaunchAppAsChainedL
// ---------------------------------------------------------------------------
//
void CLcAppLauncher::LaunchAppAsChainedL( 	  
							  TUid                    aApplicationUid,                               
                 		const TDesC&                  aCmdLineArg,
                 			  MLcAppExitObserver*     aExitObserver )
	{
	DEBUG("+ CLcAppLauncher::LaunchAppAsChainedL" )
	
	// Createt the App service object and launch the application
	CLcLaunchAppService* appService = CLcLaunchAppService::NewL();
	CleanupStack::PushL( appService );
	appService->LaunchAppL( aApplicationUid, *this, aCmdLineArg );
	CleanupStack::Pop( appService );
	
	// Transfer the ownership to this class.
	iAppService = appService;	
	isEmbeddedLaunchOutstanding = ETrue;
	
	// Store the Observer for future reference
	iExitObserver = aExitObserver;
	
	DEBUG("- CLcAppLauncher::LaunchAppAsChainedL" )	
	}
	
// ---------------------------------------------------------------------------
// void LcAppLauncher::LaunchWebBroserL
// ---------------------------------------------------------------------------
// 
void CLcAppLauncher::LaunchWebBroserL( const TDesC&              aUrl,
                                             TBool               aStandAlone,
                                             MLcAppExitObserver* aObserver )
    {
    // The parameters need to be packed in the order specified by the browser.
    // Parameters are separated by space
    // 1st parameter: Type of the second parameter. In this case 4 to indicate
    //                that the second parameter is a URL.
    // 2nd parameter: URL that needs to be launched in the browser.
    // Since we have to pack "4 " before the URL name, the total length of
    // the parameter string should be Length of the URL + 2.
    HBufC* param = HBufC::NewLC(( 2 + aUrl.Length()));
    param->Des().Append( KLcFourSpace );
    param->Des().Append( aUrl );
    
    if ( aStandAlone )
        {
        // The URL is launched in the Browser. Set the Browser UID as the UID
        // of the application which needs to be launched.
        const TInt KBrowserUid = 0x10008D39;
        TUid id( TUid::Uid( KBrowserUid ) );
        
        // Check if the Browser application is already running. Incase its
        // running Open this URL in the browser.
        TApaTaskList taskList( CEikonEnv::Static()->WsSession() );
        TApaTask task = taskList.FindApp( id );
        if ( task.Exists() )
            {
            // The browser is running. Launch the URL.
            HBufC8* param8 = HBufC8::NewLC( param->Length() );
            param8->Des().Append( *param );
            task.SendMessage( TUid::Uid( 0 ), *param8 ); // UID is not used
            CleanupStack::PopAndDestroy();
            }
        else 
            {
            // The browser is not running. Start the browser application with
            // the specified parameter. This is done by launching the browser with
            // a document name as the URL.
            RApaLsSession appArcSession;
            
            // Connect to the Application architecture server.
            User::LeaveIfError( appArcSession.Connect());
            CleanupClosePushL( appArcSession );
            TThreadId id;
            
            // Start the browser with the URL
            User::LeaveIfError( appArcSession.StartDocument( *param, 
                                                             TUid::Uid( KBrowserUid ),
                                                             id ));
            CleanupStack::PopAndDestroy( &appArcSession );
            }        
        }
    else
        {
        
        if ( !iBrowserLauncher )
            {
            // Create the Browser instance    
            iBrowserLauncher = CSchemeHandler::NewL( aUrl );
            }
            
        // Launch the Web URL in a browser in the Embedded mode.
        iBrowserLauncher->HandleUrlEmbeddedL();
        iBrowserLauncher->Observer( this );
            
        // Set the Observer incase we need to notify the termination of the
        // browser                                              
        aObserver ? ( iExitObserver = aObserver ) : NULL;
        
        isEmbeddedLaunchOutstanding = ETrue;      
        }
    CleanupStack::PopAndDestroy( param ); // param
    
    }

// ---------------------------------------------------------------------------
// void LcAppLauncher::LaunchContentL
// ---------------------------------------------------------------------------
//    
void CLcAppLauncher::LaunchContentL( const TDesC&       		aFileName,
    						   			   TBool                aStandAlone,
    						   			   MLcAppExitObserver*  aObserver )
    {
    if ( !iDocHandler )
    	{
    	iDocHandler = CDocumentHandler::NewL();
    	iDocHandler->SetExitObserver( this );
    	}
   
    TDataType dataType;    
    if ( aStandAlone )
    	{
	   	// The return values are ignored since, the User Cancelling the event doesnt
	   	// make any difference to the Client Application	
	    User::LeaveIfError( iDocHandler->OpenFileL( aFileName, dataType ));      	
    	}
	else
		{
		iExitObserver = aObserver;
	   	// The return values are ignored since, the User Cancelling the event doesnt
	   	// make any difference to the Client Application	
	    User::LeaveIfError( iDocHandler->OpenFileEmbeddedL( aFileName, dataType ));
	    
        isEmbeddedLaunchOutstanding = ETrue;	    	
		}    	
    }

// ---------------------------------------------------------------------------
// void LcAppLauncher::HandleServerAppExit
// ---------------------------------------------------------------------------
//    
void CLcAppLauncher::HandleServerAppExit( TInt aReason )
    {
    isEmbeddedLaunchOutstanding = EFalse;
    
    // Delete the App Service
  	delete iAppService;
  	iAppService = NULL;    
  	
    MLcAppExitObserver* observer = iExitObserver;        
    if ( observer )
    	{
    	// Once the request has been issued we can NULLify the observer. Nullifying
	    // it before the actual callback to faciliate the launching of another app
	    // with an exit observer when the call is executed.
	    iExitObserver = NULL;
    
    	TRAP_IGNORE( observer->HandleChainedLocationAppExitL( aReason ));
    	}
    	
	MAknServerAppExitObserver::HandleServerAppExit( aReason );	  
    }

// End of File