locationrequestmgmt/networkrequesthandler/src/x3phandler.cpp
changeset 0 9cfd9a3ee49c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/locationrequestmgmt/networkrequesthandler/src/x3phandler.cpp	Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,636 @@
+/*
+* Copyright (c) 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:
+*
+*/
+
+#include <e32base.h>
+#include <e32std.h>
+
+// LBS-specific
+#include <lbs.h>
+#include <lbs/lbsx3p.h>
+#include "lbsdevloggermacros.h"
+
+#include "lbsnrhserver.h"
+#include "x3phandler.h"
+#include "ngmessageswitch.h"
+
+
+const TInt KReservedRequestsNum = 4;
+
+
+CX3pHandler::CX3pHandler(CNGMessageSwitch& aMessageSwitch, MX3pStatusHandler& aX3pStatusHandler, CLbsAdmin& aLbsAdmin) : 
+	iMessageSwitch(aMessageSwitch),
+	iNextSessionId(1),
+	iAdmin(aLbsAdmin),
+	iReceivedFinalNetPosInfo(EFalse),
+	iX3pStatusHandler(aX3pStatusHandler)
+    {
+	
+    }
+
+CX3pHandler* CX3pHandler::NewL(CNGMessageSwitch& aMessageSwitch, MX3pStatusHandler& aX3pStatusHandler, CLbsAdmin& aLbsAdmin)
+    {
+	CX3pHandler* self;
+	self = new (ELeave) CX3pHandler(aMessageSwitch, aX3pStatusHandler, aLbsAdmin);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);	
+    }
+
+CX3pHandler::~CX3pHandler()
+	{
+	iX3pObservers.Close();
+	iX3pRequests.ResetAndDestroy();
+	}
+    
+void CX3pHandler::ConstructL()
+    {
+	iMessageSwitch.RegisterObserver(this);
+	TInt err = iAdmin.Get(KLbsSettingBehaviourMode, iLbsBehaviourMode);
+	if (err != KErrNone)
+		{
+		iLbsBehaviourMode = CLbsAdmin::ELbsBehaviourCustom1;
+		}	
+	
+	// get device mode capabilities:
+	err = LbsModuleInfo::GetDeviceCapabilities(KLbsGpsLocManagerUid, iDeviceGpsModeCaps);
+	if(err != KErrNone)
+		{
+		// Assume module supports hybrid if it has not reported its capabilities in module info file
+		iDeviceGpsModeCaps = TPositionModuleInfoExtended::EDeviceGpsModeSimultaneousTATB;
+		}
+	
+	iX3pRequests.ReserveL(KReservedRequestsNum);
+	iX3pObservers.ReserveL(KReservedRequestsNum);
+	
+    iActiveRequestIndex = KErrNotFound;
+    
+    UpdateX3pStatus();
+    }
+
+void CX3pHandler::TransmitLocationRequestL(const TDesC& aDestinationID,
+										   TUint aTransmitPriority, 
+										   const TLbsTransmitPositionOptions& aTransmitOptions,
+										   TLbsNetSessionIdInt& aSessionId)
+	{
+	LBSLOG(ELogP1, "CX3pHandler::TransmitLocationRequestL:");
+	
+	// Generate a new session Id
+	TLbsNetSessionIdInt sessionId(KLbsNetRequestHandlerUid, iNextSessionId++);
+
+    // Create an instance for this request.
+    CX3pRequest* newRequest = 0;
+	newRequest = CX3pRequest::NewL(this, sessionId,
+								   aDestinationID,
+								   aTransmitPriority,
+								   aTransmitOptions);
+	CleanupStack::PushL(newRequest);
+	iX3pRequests.AppendL(newRequest);
+	CleanupStack::Pop(newRequest);
+	
+	// Write the session Id back to the caller
+	aSessionId = sessionId;
+
+    //
+    // The timeout (if specified) runs from the time the request was made, so 
+    // start the request timer now, even if we're not going to action the 
+    // request yet
+    //
+	newRequest->StartTimer();
+	
+	//
+	// The new request has been added. Now see if there is a request being
+	// actioned at the moment. If not, start this one
+	//
+	TInt newRequestIndex = iX3pRequests.Count() - 1;
+	TInt currentRequestIndex = iActiveRequestIndex;
+	if(iActiveRequestIndex == KErrNotFound)
+	    {
+		currentRequestIndex = newRequestIndex;
+	    }
+	else
+	    {
+        // 
+        // If there is an active request, see if its priority is lower than 
+        // the new one. If so, action the new one.
+        // The Network Gateway handles the necessary cancellations.
+        //
+        if(iActiveRequest->TransmitPriority() > aTransmitPriority)
+            {
+            LBSLOG3(ELogP2, "New X3P (priority %d) overrides currently active X3P (priority %d)", 
+            				aTransmitPriority, 
+            				iActiveRequest->TransmitPriority());
+            				
+		    currentRequestIndex = newRequestIndex;
+            }
+	    }
+	if(currentRequestIndex != iActiveRequestIndex)
+	    {
+	    iActiveRequestIndex = currentRequestIndex;
+		ActivateRequest();
+	    }
+	}
+
+void CX3pHandler::TransmitLocationCancel(const TLbsNetSessionIdInt& aSessionId)
+	{
+	LBSLOG(ELogP1, "CX3pHandler::TransmitLocationCancel:");
+
+	// There is a chance that we get a 'cancel' for an X3P request
+	// that has already finished normally, so first check that
+	// the sessionId is one that is currently active.
+	TInt requestIndex = FindSessionById(aSessionId);
+	if(requestIndex != KErrNotFound)
+		{
+		// Forward the cancel message onto the network
+		iMessageSwitch.SendX3pCancel(aSessionId, KErrCancel);
+		}
+	}
+    
+void CX3pHandler::ActivateRequest()	    
+	{
+	if(iActiveRequestIndex != KErrNotFound)
+		{
+		iActiveRequest = iX3pRequests[iActiveRequestIndex];
+		
+		// Get the technology type to use for this request from the admin settings.
+		TPositionModuleInfo::TTechnologyType mode;
+		GetAdminTechnologyType(mode);
+		TLbsNetPosRequestOptionsTechnologyInt options;
+		options.SetPosMode(mode);
+		
+		iMessageSwitch.SendX3pRequest(iActiveRequest->SessionId(),
+									  iActiveRequest->DestinationId(),
+									  iActiveRequest->TransmitPriority(),
+									  options);
+		
+		// Reset the final network position flag
+		iReceivedFinalNetPosInfo = EFalse;
+		}
+	}
+
+/* Called when a pending request has timed out before it was completed.
+ */
+void CX3pHandler::OnRequestTimeout(const TLbsNetSessionIdInt& aTimedOutRequestId)
+    {
+	if(aTimedOutRequestId.SessionNum() != 0)
+		{
+		HandleTimedOutRequest(aTimedOutRequestId);
+		}
+    }
+
+/*
+*/
+TInt CX3pHandler::HighestPriorityIndex()
+    {
+    TInt index = KErrNotFound;
+    const TInt count = iX3pRequests.Count();
+    if (count > 0)
+    	{
+    	CX3pRequest* highPriorityReq = iX3pRequests[0];
+    	index = 0;
+    	for (TInt i = 1; i < count; i++)
+    		{
+    		CX3pRequest* request = iX3pRequests[i];
+    		if (request->TransmitPriority() > 
+    			highPriorityReq->TransmitPriority())
+    			{
+    			index = i;
+    			highPriorityReq = request;
+    			}
+    		}
+   		}
+
+	return (index);
+	}
+
+
+/* Look through the array of requests to find the one with a session Id
+   equal to the input aSessionId.
+   
+   Set the reference parameter aSessionIndex to the array index of the
+   request, and return a pointer to the request.
+   If no request is found with the specified aSessionId, then return NULL.
+*/
+TInt CX3pHandler::FindSessionById(const TLbsNetSessionIdInt& aSessionId)
+    {
+    TInt retVal = KErrNotFound;
+	TInt requestCount = iX3pRequests.Count();
+	for (TInt i = 0; i < requestCount; ++i)
+	    {
+		if(iX3pRequests[i]->SessionId() == aSessionId)
+		    {
+		    retVal = i;
+		    break;
+		    }
+	    }
+	return(retVal);    
+    }
+
+/* Search the array following a delete to find the index
+   of the currently active request, looking for it by its session ID.
+*/
+void CX3pHandler::RecalculateActiveIndex(const TLbsNetSessionIdInt& aSessionId)
+    {
+	iActiveRequestIndex = FindSessionById(aSessionId);
+    }
+
+void CX3pHandler::HandleTimedOutRequest(const TLbsNetSessionIdInt& aRequestId)
+    {
+	// Send a cancel message to the network,
+	//  with KErrTimedOut as the reason
+	iMessageSwitch.SendX3pCancel(aRequestId, KErrTimedOut);	
+    }
+
+
+void CX3pHandler::HandleCompletedRequest(const TLbsNetSessionIdInt& aRequestId, TInt aReason)
+    {
+    TInt err = aReason;
+    TBool isTerminalAssistedPos = EFalse;
+    //
+    // There's a possibility this request ID won't be found, if a Transmit
+    // Cancel was received after the request had been sent off. If this
+    // is the case, just ignore the completion.
+    //
+	TInt requestIndex = FindSessionById(aRequestId);
+	if(requestIndex != KErrNotFound)
+		{
+		if (!iReceivedFinalNetPosInfo)
+			{
+			TInt ret = iMessageSwitch.GetNetworkFinalPosition(aRequestId, iFinalNetPosInfo);
+			if (err == KErrNone && ret != KErrNone)
+				{
+				err = ret;
+				}
+			}
+
+		// Add the ID of the module supplying the update. This is either 
+		// the GPS Location Manager or the Network Location Manager (if 
+		// the Position Mode is not one of those below, leave the Module Id
+		// unchanged).
+		TPositionModuleInfo::TTechnologyType posMode = iFinalNetPosInfo.PositionMode();
+		if(posMode == (TPositionModuleInfo::ETechnologyTerminal | TPositionModuleInfo::ETechnologyAssisted))
+			{
+			iFinalNetPosInfo.SetModuleId(KLbsGpsLocManagerUid);
+			}
+		else
+			if(posMode == (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted))
+				{
+				iFinalNetPosInfo.SetModuleId(KLbsNetLocManagerUid);
+				isTerminalAssistedPos = ETrue;
+				}
+
+		// It may be that the network has modified the position update, 
+		// so we need to check that it satisfies the quality criteria and report
+		// it if not.
+		if(aReason == KErrNone) // network thinks it's OK
+			{
+			if(!iX3pRequests[requestIndex]->FixIsAccurate(iFinalNetPosInfo, isTerminalAssistedPos))
+				{
+				err = KPositionQualityLoss;
+				}
+			}
+				
+		// Notify observers of the completed session
+		const TInt count = iX3pObservers.Count();
+		for (TInt i = 0; i < count; i++)
+			{
+			iX3pObservers[i]->OnTransmitLocationComplete(
+									aRequestId, 
+									iFinalNetPosInfo,
+									err);
+			}
+		
+		// Remove the request from the list
+		delete iX3pRequests[requestIndex];
+		iX3pRequests.Remove(requestIndex);
+
+		// If the completed request was being actioned, start the next
+		// one if there is one.
+		if(requestIndex == iActiveRequestIndex)
+			{
+			iActiveRequestIndex = HighestPriorityIndex();
+			if(iActiveRequestIndex != KErrNotFound)
+				{
+				ActivateRequest();
+				}
+		}
+		else
+			{
+			// The array has been changed by the removal of an entry.
+			// Make sure iActiveRequestIndex is correct for the active
+			// entry.
+			TLbsNetSessionIdInt activeSessionId = iActiveRequest->SessionId();
+			RecalculateActiveIndex(activeSessionId);
+			}    
+		}
+	
+ 	// Tell the AGPS interface handler the current state
+ 	// of the X3P handler.
+ 	UpdateX3pStatus();
+	}
+
+/*
+*/
+void CX3pHandler::OnMTLRRequest(const TLbsNetSessionIdInt& /*SessionId*/,
+				  TLbsNetworkEnumInt::TLbsNetProtocolServiceInt  /*aSessionType*/, 
+				   TBool /*aIsEmergency*/,
+				   const TLbsExternalRequestInfo& /*aExternalRequestInfo*/,
+				   const TLbsNetPosRequestPrivacyInt& /*aNetPosRequestPrivacy*/)
+	{
+	// We do not need to know about MT-LR requests so ignore this call.
+	}
+
+void CX3pHandler::OnNetLocResponse(const TLbsNetSessionIdInt& aSessionId,
+								 const TLbsNetPosRequestQualityInt& aQuality)
+	{
+	// Check if this Network Location Response
+	// is for a X3P that is currently in progress
+	TInt requestIndex = FindSessionById(aSessionId);
+	if (requestIndex != KErrNotFound)
+		{
+		iX3pRequests[requestIndex]->SetRequestQuality(aQuality);
+		}
+	}
+
+/*
+*/
+void CX3pHandler::OnSessionComplete(const TLbsNetSessionIdInt& aSessionId, TInt aReason)
+	{
+	// Check if this Network Location Response
+	// is for a X3P that is currently in progress
+	TInt requestIndex = FindSessionById(aSessionId);
+	if (requestIndex != KErrNotFound)
+		{
+		HandleCompletedRequest(aSessionId, aReason);
+		}
+	}
+
+/* Called during a TransmitLocation request, at the point where the network provides the
+handset with a network-based Reference Location.
+
+The Reference Location (aRefPosInfo) will be sent back to the client's session, and the session
+will forward it back to the client if the client wants it.
+
+Values of aIsEmengency and aQuality are not relevant for the CX3pHandler (they are for
+other observers)
+*/
+void CX3pHandler::OnNetLocRequest(const TLbsNetSessionIdInt& aSessionId,
+					const TLbsNetPosRequestMethodInt& aNetPosMethod,
+					 TLbsNetworkEnumInt::TLbsNetProtocolServiceInt /*aSessionType*/, 
+					 TBool /*aIsEmergency*/,
+					 const TLbsNetPosRequestQualityInt& /*aQuality*/)
+	{
+	TBool hybridMode = EFalse;
+	TLbsNetPosMethodInt posMethod;
+	
+	const TPositionModuleInfo::TTechnologyType KTerminalAssistedMode = (
+				TPositionModuleInfo::ETechnologyNetwork |
+				TPositionModuleInfo::ETechnologyAssisted);
+				
+	// Does the hardware support hybrid mode?
+	if(iDeviceGpsModeCaps & TPositionModuleInfoExtended::EDeviceGpsModeSimultaneousTATB )
+		{
+		TInt methodCount = aNetPosMethod.NumPosMethods();
+		for(TInt i = 0; (i < methodCount) && !hybridMode; ++i)
+			{
+			aNetPosMethod.GetPosMethod(i, posMethod);
+			hybridMode = (posMethod.PosMode() & KTerminalAssistedMode) == KTerminalAssistedMode;
+			}
+		}
+	
+	// Custom1: If the hybrid mode and a first request, then re-start the timer
+	if (hybridMode 
+		&& (aSessionId.SessionOwner() == KLbsNetRequestHandlerUid) 
+		&& (iLbsBehaviourMode == CLbsAdmin::ELbsBehaviourCustom1))
+		{
+		TInt requestIndex = FindSessionById(aSessionId);
+		if(requestIndex != KErrNotFound)
+			{
+			// The timer can be re-started only once
+			iX3pRequests[requestIndex]->ReStartTimerOnce();
+	   		}
+	   	}
+	}
+
+/** Called when a reference position arrives from the network.
+*/
+void CX3pHandler::OnNetLocReferenceUpdate(const TLbsNetSessionIdInt& aSessionId, 
+								 		  const TPositionInfoBase& aPosInfo)
+	{
+    // There's a possibility this request ID won't be found, if a Transmit
+    // Cancel was received after the request had been sent off. If this
+    // is the case, just ignore the completion.
+	if (aSessionId.SessionOwner() == KLbsNetRequestHandlerUid)
+		{
+		iRefPosInfo = static_cast<const TPositionInfo&>(aPosInfo);
+
+		TInt requestIndex = FindSessionById(aSessionId);
+		if(requestIndex != KErrNotFound)
+			{
+			iRefPosInfo.SetModuleId(KLbsGpsLocManagerUid);
+			iRefPosInfo.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork);
+			iRefPosInfo.SetPositionModeReason(EPositionModeReasonNone);
+			iRefPosInfo.SetUpdateType(EPositionUpdateGeneral);
+		
+	   		// Notify observers of the completed session
+	   		const TInt count = iX3pObservers.Count();
+	   		for (TInt i = 0; i < count; i++)
+	   			{
+	   			iX3pObservers[i]->OnReferenceLocationAvailable(
+	   									aSessionId, 
+	  									iRefPosInfo);
+	   			}
+	   		}
+	   	}	
+	}
+
+/** Callend when a final location arrives from the network.
+*/
+void CX3pHandler::OnNetLocFinalUpdate(
+		const TLbsNetSessionIdInt& aSessionId, 
+		const TPositionInfoBase& aPosInfo)
+	{
+	// If the final network position is for an active X3P, 
+	// then store it for when the X3P is completed.
+	TInt requestIndex = FindSessionById(aSessionId);
+	if (requestIndex != KErrNotFound)
+		{
+		if (requestIndex == iActiveRequestIndex)
+			{
+			iReceivedFinalNetPosInfo = ETrue;
+			iFinalNetPosInfo = static_cast<const TPositionInfo&>(aPosInfo);
+			}
+		}
+	}
+
+TInt CX3pHandler::OnTransmitPosition(const TDesC& aDestinationId,
+									 TUint aTransmitPriority,
+									 const TLbsTransmitPositionOptions& aTransmitOptions,
+									 TLbsNetSessionIdInt& aSessionId)
+	{
+	TInt err(KErrNone);
+	TRAP(err, TransmitLocationRequestL(aDestinationId, aTransmitPriority,
+									   aTransmitOptions, aSessionId));
+	
+ 	// Tell the AGPS interface handler the current state
+ 	// of the X3P handler.
+ 	UpdateX3pStatus();
+	
+	return err;
+	}
+	
+void CX3pHandler::OnCancelTransmitPosition(const TLbsNetSessionIdInt& aSessionId)
+	{
+	TransmitLocationCancel(aSessionId);
+	}
+
+/* Add an observer (actually a client X3P subsession)
+*/
+void CX3pHandler::AddObserverL(MX3pHandlerObserver* aObserver)
+ 	{
+ 	iX3pObservers.AppendL(aObserver);
+ 	
+ 	// Tell the AGPS interface handler the current state
+ 	// of the X3P handler.
+ 	UpdateX3pStatus();
+ 	}
+
+/* Remove an observer (actually a client X3P subsession)
+*/
+void CX3pHandler::RemoveObserver(MX3pHandlerObserver* aObserver)
+ 	{
+ 	TInt index = iX3pObservers.Find(aObserver);
+ 	if (index != KErrNotFound)
+ 		{
+ 		iX3pObservers.Remove(index);
+ 		}
+ 
+ 	// Tell the AGPS interface handler the current state
+ 	// of the X3P handler.
+ 	UpdateX3pStatus();
+ 	}
+
+/** Send the current X3P status to the status handler - for power mode advice.
+*/
+void CX3pHandler::UpdateX3pStatus()
+	{
+	
+	MX3pStatusHandler::TX3pStatus status(MX3pStatusHandler::EX3pStatusIdle);
+	if (iActiveRequestIndex != KErrNotFound)
+		{
+		// There is a currently active request, so we are 'active'
+		status = MX3pStatusHandler::EX3pStatusActive;
+		}
+	else
+		{
+	 	if (iX3pObservers.Count() >= 1)
+	 		{
+		 	// If there is one or more observer (i.e. session) in the array,
+		 	// then set the X3P status to 'connected', in case the GPS hardware
+		 	// needs to be informed to go into a warm-up state.
+	 		status = MX3pStatusHandler::EX3pStatusConnected;
+	 		}
+	 	else if (iX3pObservers.Count() == 0)
+	 		{
+	 	 	// If there are no observers (i.e. sessions), then tell
+	 	 	// the X3P status handler that we are 'idle', since there are no
+	 	 	// outstanding X3P requests or sessions connected.
+	 		status = MX3pStatusHandler::EX3pStatusIdle;
+	 		}
+		}
+	// Update the X3P status. 
+	iX3pStatusHandler.SetX3pStatus(status);
+	}
+
+void CX3pHandler::GetAdminTechnologyType(TPositionModuleInfo::TTechnologyType& aMode)
+	{
+	aMode = TPositionModuleInfo::ETechnologyUnknown;
+	
+	// Determine the current technology type from the admin settings
+	RLbsNetworkRegistrationStatus lbsNetRegStatus;
+	TRAPD(err, lbsNetRegStatus.OpenL());
+	if(err != KErrNone)
+	    {
+        // Netreg status could not be determined mode will be ETechnologyUnknown
+        return;
+	    }
+    RLbsNetworkRegistrationStatus::TLbsNetworkRegistrationStatus netRegStatus;
+    err = lbsNetRegStatus.GetNetworkRegistrationStatus(netRegStatus);
+	lbsNetRegStatus.Close();			    
+    if (err == KErrNone)
+    	{
+    	TLbsAdminSetting setting;
+    	switch (netRegStatus)
+    		{
+    		case RLbsNetworkRegistrationStatus::ERegisteredHomeNetwork:
+    			setting = KLbsSettingHomeGpsMode;
+    			break;
+    		case RLbsNetworkRegistrationStatus::ERegisteredRoamingNetwork:
+    			setting = KLbsSettingRoamingGpsMode;
+				break;
+    		default:
+    			// default to using the roaming setting
+    			LBSLOG_WARN2(ELogP3, 
+    						 "CX3pHandler::GetAdminTechnologyType: unkown network registration status (%d), defaulting to roaming.", 
+    						 netRegStatus);
+    			setting = KLbsSettingRoamingGpsMode;
+    			break;
+    		}
+    	
+		CLbsAdmin::TGpsMode gpsMode;
+		err = iAdmin.Get(setting, gpsMode);
+		if (err == KErrNone)
+			{
+			switch (gpsMode)
+				{
+				case CLbsAdmin::EGpsModeUnknown:
+					aMode = (TPositionModuleInfo::ETechnologyUnknown);
+					break;
+					
+				case CLbsAdmin::EGpsPreferTerminalBased:
+					aMode = (TPositionModuleInfo::ETechnologyTerminal | TPositionModuleInfo::ETechnologyAssisted);
+					break;
+					
+				case CLbsAdmin::EGpsAlwaysTerminalBased:
+					aMode = (TPositionModuleInfo::ETechnologyTerminal | TPositionModuleInfo::ETechnologyAssisted);
+					break;
+					
+				case CLbsAdmin::EGpsAutonomous:
+					aMode = (TPositionModuleInfo::ETechnologyTerminal);
+					break;
+					
+				case CLbsAdmin::EGpsPreferTerminalAssisted:
+					aMode = (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted);
+					break;
+					
+				case CLbsAdmin::EGpsAlwaysTerminalAssisted:
+					aMode = (TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted);
+					break;
+				
+				default:
+					aMode = (TPositionModuleInfo::ETechnologyUnknown);
+					 			// default to using the roaming setting
+    				LBSLOG_WARN2(ELogP3, 
+    						 "CX3pHandler::GetAdminTechnologyType: unkown TGpsMode (%d), defaulting to TPositionModuleInfo::ETechnologyUnknown.", 
+    						 gpsMode);
+					break;
+				}
+			}
+	   	}
+	}
+
+