locationrequestmgmt/locationserver/src/EPos_CPosLastKnownPosAreaHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:38:06 +0300
branchRCL_3
changeset 54 0c2046328c85
parent 0 9cfd9a3ee49c
permissions -rw-r--r--
Revision: 201027 Kit: 201035

/*
* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  	This class inherits the common functionalities for requests to the 
*				Location Monitor from EPos_CPosLocMonitorReqHandlerBase.h and also
*				implements the functions specific to Last Known Position Area request.
*
*/




#include "EPos_CPosLastKnownPosAreaHandler.h"
#include  "EPos_CPosCallbackTimer.h"

// ============================ CONSTANTS ===========================================================
#ifdef _DEBUG
_LIT(KTraceFileName, "EPos_CPosLastKnownPosAreaHandler.cpp");
#endif

// ============================== MEMBER FUNCTIONS ===================================================
CPosLastKnownPosAreaHandler* CPosLastKnownPosAreaHandler::NewL()
	{
	CPosLastKnownPosAreaHandler* self = new( ELeave ) CPosLastKnownPosAreaHandler();
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop( self );
	return self;
	}

CPosLastKnownPosAreaHandler::CPosLastKnownPosAreaHandler()
	{
	CActiveScheduler::Add(this);
	}

void CPosLastKnownPosAreaHandler::ConstructL()
	{
    TCallBack timeoutCallBack(HandleTimeOut, this);
    iTimeoutTimer = CPosCallbackTimer::NewL(timeoutCallBack);
	}

CPosLastKnownPosAreaHandler::~CPosLastKnownPosAreaHandler()
	{
	
	if (iStatus==KRequestPending)
		{
		// Cancel the request sent to the location monitor
		Cancel();
		}

	if ( iLocMonAreaPositioner.SubSessionHandle() )
		{
		iLocMonAreaPositioner.Close();
		}
	
	delete iTimeoutTimer;
	
	// The requests on the queue are completed by the base class destructor
	}

/** 
 * GetLastKnownPosAreaL 
 * 		>>  Initiate a new request with the location monitor if the request queue is empty. 
 * 			Otherwise, check if the session and subsession id of any request on the queue matches that of the 
 *			new request [ie. a duplicate request from the client]. If it matches panic the client. 
 * 			If not add the new request to the queue. 
 *
 * @param  aLocMonSession    - The handle to the session with the location monitor passed on from
 * 							   CPosLocMonitorReqHandlerHub.
 * @param  aMessage  		 - The new request from the client 
 */
void CPosLastKnownPosAreaHandler::GetLastKnownPosAreaL(RLbsLocMonitorSession& aLocMonSession, const RMessage2& aMessage)
	{
	DEBUG_TRACE("CPosLastKnownPosAreaHandler::GetLastKnownPosAreaL", __LINE__)

	if ( !(aLocMonSession.Handle()))
		{
		// Session with the location monitor is not found
		RequestComplete(aMessage, KErrCouldNotConnect);
		return;
		}

	if (!(iLocMonAreaPositioner.SubSessionHandle()))
		{
		iLocMonAreaPositioner.OpenL(aLocMonSession);
		}
	
	// Copy the buffers from the address space of the client
	HBufC8* lkposclientbuf = Global::CopyClientBuffer8LC(aMessage, KParamLKPAreaReqPos);
	HBufC8* lkposareaclientbuf = Global::CopyClientBuffer8LC(aMessage, KParamLKPAreaReqArea);

	TPositionInfoBase& posInfoBase = reinterpret_cast<TPositionInfoBase&>
	(const_cast<TUint8&>(*lkposclientbuf->Ptr()));
	TPositionAreaInfoBase& posAreaInfoBase = reinterpret_cast<TPositionAreaInfoBase&>
	(const_cast<TUint8&>(*lkposareaclientbuf->Ptr()));

	Global::ValidatePositionClassBufferL(posInfoBase, lkposclientbuf->Des());
	Global::ValidatePositionClassTypeL(posInfoBase, EPositionInfoClass, KErrArgument);
	Global::ValidatePositionClassBufferL(posAreaInfoBase, lkposareaclientbuf->Des());

	switch (posAreaInfoBase.PositionClassType())
		{
		case EPositionAreaInfoClass:
			Global::ValidatePositionClassTypeL(posAreaInfoBase, EPositionAreaInfoClass, KErrArgument);
			break;
		case (EPositionAreaExtendedInfoClass+EPositionAreaInfoClass): //TODO Check LbsAreaInfo.cpp [constructor]
			Global::ValidatePositionClassTypeL(posAreaInfoBase, (EPositionAreaExtendedInfoClass+EPositionAreaInfoClass), KErrArgument);
			break;
		default:
			User::Leave(KErrArgument); 								//TODO - Check if this is correct ?
			break;
		}

	CleanupStack::PopAndDestroy(lkposareaclientbuf);
	CleanupStack::PopAndDestroy(lkposclientbuf);

	// Check the identity of the subsession and add the request to the queue
	CheckAndAddReqToQueueL(EReqOnSubSession, aMessage);
	
	if ((iLocMonitorReqQ.Count()>0) && !IsActive())
		{
		// Always ask for extended information from the location monitor
		// as initiating a new request for later clients that require extended information
		// is inefficient
		iParameters.iPositionAreaType = (EPositionAreaExtendedInfoClass | EPositionAreaInfoClass);
		
		// Initiate a new last known position request with the location monitor
		iLocMonAreaPositioner.GetLastKnownPositionArea(iPositionInfo, iPositionAreaInfo, iParameters, iStatus);
		SetActive();
		
	    // Start timer if necessary
	    if (KLastKnownPosAreaTimeOut.Int64()>0)
	        {
	        DEBUG_TRACE("CPosLastKnownPosHandler::GetLastKnownPosAreaL() Start Timeout Timer", __LINE__)
	        iTimeoutTimer->StartTimer(KLastKnownPosAreaTimeOut);
	        }
		}

	}

/** 
 * CancelGetLastKnownPosAreaL 
 * 		>> Cancel the outstanding request with the location monitor if there is only one request on the queue. 
 *		>> Otherwise just complete the cancel request with KErrNone, remove the original request from the queue
 * 		   and complete it with KErrCancel.
 * @param  aMessage  		 - The cancel request from the client 
 */
void CPosLastKnownPosAreaHandler::CancelGetLastKnownPosAreaL(const RMessage2& aMessage)
	{
	DEBUG_TRACE("CPosLastKnownPosAreaHandler::CancelGetLastKnownPosAreaL", __LINE__)

	// The subsession with the location monitor is not found
	if ( !(iLocMonAreaPositioner.SubSessionHandle()) )
		{
		RequestComplete(aMessage, KErrNotFound);
		return;
		}
	
	// Call CancelRequest inherited from the baseclass
	CancelRequest(EReqOnSubSession, aMessage);

	}

/** 
 * NotifyOnEmptyLastKnownPosStoreReq 
 * 		>> Cancel the outstanding get last known position area requests with KErrCancel
 * 		   as an empty last known position store request has been issued.
 */
void  CPosLastKnownPosAreaHandler::NotifyOnEmptyLastKnownPosStoreReq()
	{
	// Complete all the requests on the queue with KErrCancel
	QRequestsComplete(KErrCancel);
	
	if (iStatus==KRequestPending)
		{
		Cancel();
		}
	}

/** 
 * RunL 
 * 		>> Complete all the requests on the queue.
 */
void CPosLastKnownPosAreaHandler::RunL()
	{
	
	// Cancel the timeout timer
	iTimeoutTimer->Cancel();
	
	// Serving all the outstanding requests based on the current update
	// from the Location Monitor
	while (iLocMonitorReqQ.Count()>0)
		{
		TInt numReqs = iLocMonitorReqQ.Count()-1;
		// Retrieve the next request to be serviced [first element in the queue - FIFO]
		if (iStatus.Int()==KErrNone)
			{
			// Copy the buffers from the address space of the client
			const TUint8* startAddress = reinterpret_cast <const TUint8*>(&iPositionInfo)+sizeof(TPositionClassTypeBase);
			TInt chunkSize = sizeof(TPositionInfo)-sizeof(TPositionClassTypeBase);
			TPtr8 copyFromDesc(const_cast<TUint8*>(startAddress),chunkSize,chunkSize);
			
			TInt err = Global::Write(iLocMonitorReqQ[numReqs],KParamLKPAreaReqPos,copyFromDesc,sizeof(TPositionClassTypeBase));
			//TInt err = iLocMonitorReqQ[numReqs].Write(KParamLKPAreaReqPos,copyFromDesc,sizeof(TPositionClassTypeBase));

			// To identify the type of the request - last known position area / last known position area + extended info.
			HBufC8* lkposareaclientbuf = Global::CopyClientBuffer8LC(iLocMonitorReqQ[numReqs], KParamLKPAreaReqArea);
			TPositionAreaInfoBase& posAreaInfoBase = reinterpret_cast<TPositionAreaInfoBase&>(const_cast<TUint8&>(*lkposareaclientbuf->Ptr()));
			startAddress = reinterpret_cast <const TUint8*>(&iPositionAreaInfo)+sizeof(TPositionClassTypeBase);
			
			switch (posAreaInfoBase.PositionClassType())
				{
				case EPositionAreaInfoClass:
					chunkSize = sizeof(TPositionAreaInfo)-sizeof(TPositionClassTypeBase);
					copyFromDesc.Set(const_cast<TUint8*>(startAddress),chunkSize,chunkSize);
					//err = iLocMonitorReqQ[numReqs].Write(KParamLKPAreaReqArea,copyFromDesc,sizeof(TPositionClassTypeBase));
					err = Global::Write(iLocMonitorReqQ[numReqs],KParamLKPAreaReqArea,copyFromDesc,sizeof(TPositionClassTypeBase));
					RequestComplete(iLocMonitorReqQ[numReqs], err);
					break;
				case (EPositionAreaExtendedInfoClass+EPositionAreaInfoClass): //TODO Check LbsAreaInfo.cpp [constructor]
					chunkSize = sizeof(TPositionAreaExtendedInfo)-sizeof(TPositionClassTypeBase);
					copyFromDesc.Set(const_cast<TUint8*>(startAddress),chunkSize,chunkSize);
					err = Global::Write(iLocMonitorReqQ[numReqs],KParamLKPAreaReqArea,copyFromDesc,sizeof(TPositionClassTypeBase));
					//err = iLocMonitorReqQ[numReqs].Write(KParamLKPAreaReqArea,copyFromDesc,sizeof(TPositionClassTypeBase));		
					RequestComplete(iLocMonitorReqQ[numReqs], err);
					break;
				default:
					RequestComplete(iLocMonitorReqQ[numReqs], KErrArgument);								//TODO - Check if this is correct ?
					break;
				}
			// Destroy the buffer used to hold the client's data
			CleanupStack::PopAndDestroy(lkposareaclientbuf);
			
			}
		else
			{
			// Complete the client request with aReason
			RequestComplete(iLocMonitorReqQ[numReqs],iStatus.Int());
			}

		// Remove the request that has just been serviced [last element]
		iLocMonitorReqQ.Remove(numReqs);
		}
	
	// Close the subsession with the location monitor when we receive the last known position area from it
	iLocMonAreaPositioner.Close();

	}

TInt CPosLastKnownPosAreaHandler::RunError(TInt aError)
	{
	return aError;
	}


/** 
 * DoCancel 
 * 		>> Cancel the active object.
 */
void CPosLastKnownPosAreaHandler::DoCancel()
	{
	// Cancel the timer as the request with the location monitor is going to be cancelled
	iTimeoutTimer->Cancel();
	
	DEBUG_TRACE("calling RLbsAreaPositioner::CancelGetLastKnownPosition()", __LINE__)
	__ASSERT_DEBUG((iLocMonAreaPositioner.SubSessionHandle())!=NULL, DebugPanic(EPosServerPanicPositionerNotInitialized));
	
	TInt err = iLocMonAreaPositioner.CancelGetLastKnownPositionArea();
	// As the cancel request is immediately completed, this return value 
	// is not useful.
	}

/** 
 * HandleTimeOut 
 * 		>> Complete all the requests on the queue with KErrTimedOut.
 * @param  aRequestHandler - self pointer used to call the appropriate timeout handling method
 */
TInt CPosLastKnownPosAreaHandler::HandleTimeOut(TAny* aRequestHandler)
    {

    DEBUG_TRACE("CPosLastKnownPosAreaHandler::HandleTimeOut()", __LINE__)    
    
    CPosLastKnownPosAreaHandler* self = reinterpret_cast<CPosLastKnownPosAreaHandler*>(aRequestHandler);
    // The request with the location monitor has timed out. So complete all the outstanding 
    // requests with KErrTimedOut
    self->QRequestsComplete(KErrTimedOut);
    // Cancel the pending request with the location monitor
    self->Cancel();

    return KErrNone;
    
    }