diff -r 000000000000 -r 9cfd9a3ee49c locationrequestmgmt/networkrequesthandler/src/x3phandler.cpp --- /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 +#include + +// LBS-specific +#include +#include +#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(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(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; + } + } + } + } + +