--- /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;
+ }
+ }
+ }
+ }
+
+