diff -r 000000000000 -r 9cfd9a3ee49c locationrequestmgmt/locationserver/src/EPos_CPosSubSession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/locationrequestmgmt/locationserver/src/EPos_CPosSubSession.cpp Tue Feb 02 01:50:39 2010 +0200 @@ -0,0 +1,693 @@ +// Copyright (c) 2005-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 FILES +#include +#include +#ifdef SYMBIAN_FEATURE_MANAGER + #include + #include +#endif +#include +#include +#include "lbslocservermessageenums.h" +#include +#include +#include "epos_proxypositionerconstructparams.h" +#include "lbsdevloggermacros.h" + +#include "epos_cposmodulessettings.h" +#include "EPos_Global.h" +#include "EPos_ServerPanic.h" +#include "EPos_CPositionRequest.h" +#include "EPos_CPosSubSession.h" + + +#include "EPos_CPosLocMonitorReqHandlerHub.h" + +// CONSTANTS +#ifdef _DEBUG +_LIT(KTraceFileName, "EPos_CPosSubSession.cpp"); +#endif + +const TInt KParamRequestorType = 0; +const TInt KParamRequestorFormat = 1; +const TInt KParamRequestorData = 2; +const TInt KParamRequestorStack = 0; +const TInt KParamUpdateOptions = 0; + + +// ==================== LOCAL FUNCTIONS ==================== + +// --------------------------------------------------------- +// ResetAndDestroy Used for cleanup. +// This function is passed to a TCleanupItem +// --------------------------------------------------------- +// +void ResetAndDestroyRRequestorStack(TAny* aPtr) + { + (reinterpret_cast (aPtr))->ResetAndDestroy(); + } + +// ================= MEMBER FUNCTIONS ======================= + +/** + * C++ default constructor + */ +CPosSubSession::CPosSubSession() : iRequestors() + { + + } + +/** + * Symbian default constructor + */ +void CPosSubSession::ConstructL( + CPosModuleSettings& aModuleSettings, + CPosLocMonitorReqHandlerHub& aLocMonitorReqHandlerHub, + TPositionModuleId aImplementationUid, + MPosStatusObserver* aStatusObserver, + MPosModuleStatusManager* aModuleStatusManager, + TBool aIsProxy) + { + TProxyPositionerConstructParams positionerParams; + positionerParams.iImplementationUid = aImplementationUid; + positionerParams.iStatusObserver = aStatusObserver; + positionerParams.iParamObserver = this; + positionerParams.iModuleSettingsManager = &aModuleSettings; + positionerParams.iModuleStatusManager = aModuleStatusManager; + + iPositionRequest = CPositionRequest::NewL( + aModuleSettings, + aLocMonitorReqHandlerHub, + positionerParams, + aIsProxy); + + + + + //Need to call it to propogate iPsyDefaultUpdateTimeOut in case + //SetPsyDefaultUpdateTimeOut was called in the CPositionRequest::NewL + //See SetPsyDefaultUpdateTimeOut implementation + SetPsyDefaultUpdateTimeOut(iPsyDefaultUpdateTimeOut); + + iLocMonitorReqHandlerHub = &aLocMonitorReqHandlerHub; + +#ifdef SYMBIAN_FEATURE_MANAGER + iLocationManagementSupported = CFeatureDiscovery::IsFeatureSupportedL(NFeature::KLocationManagement); +#else + __ASSERT_ALWAYS(EFalse, User::Invariant()); // Would happen on older versions of symbian OS if this code ever backported +#endif + + if(iLocationManagementSupported) + { + iAdmin = CLbsAdmin::NewL(); + // connect to network registration status interface + iNetRegStatus.OpenL(); + } + } + +/** + * Two-phased constructor. + * + * @param aLastPositionHandler Last position handler. + * @param aModulesDb the position log database. + * @param aImplementationUid the positioner implementation uid. + * @param aIsProxy ETrue if aImplementationUid represents a proxy PSY, + * EFalse otherwise. + * @param aStatusObserver status observer to be used by positioner. + * @param aLocMonSession Location Monitor session handle shared by all subsessions + */ +CPosSubSession* CPosSubSession::NewLC( + CPosModuleSettings& aModuleSettings, + CPosLocMonitorReqHandlerHub& aLocMonitorReqHandlerHub, + TUid aImplementationUid, + TBool aIsProxy, + MPosStatusObserver* aStatusObserver, + MPosModuleStatusManager* aModuleStatusManager) + + { + CPosSubSession* self = new (ELeave) CPosSubSession(); + CleanupClosePushL(*self); + + self->ConstructL( + aModuleSettings, + aLocMonitorReqHandlerHub, + aImplementationUid, + aStatusObserver, + aModuleStatusManager, + aIsProxy); + + return self; + } + +/** + * Destructor. + */ +CPosSubSession::~CPosSubSession() + { + if(iLocationManagementSupported) + { + delete iAdmin; + iNetRegStatus.Close(); + } + iRequestors.ResetAndDestroy(); + delete iPositionRequest; + + } + + +/** + * This function is responsible for handling the + * servicing of client requests to the server. + * It uses the message passed as an argument to + * obtain the request opcode and to access client + * addresses for reading and writing. + * + * @param aMessage The current message + */ +void CPosSubSession::ServiceL(const RMessage2& aMessage) + { + switch (aMessage.Function()) + { + case ELbsSetSingleRequestor: + HandleSetRequestorL(aMessage); + break; + case ELbsSetMultipleRequestors: + HandleSetRequestorStackL(aMessage); + break; + case ELbsSetUpdateOptions: + HandleSetUpdateOptionsL(aMessage); + break; + case ELbsGetUpdateOptions: + HandleGetUpdateOptionsL(aMessage); + break; + case ELbsGetLastKnownPosition: + LBS_RDEBUG("Client", "LBS", "GetLastKnownPosition"); + HandleGetLastKnownPositionL(aMessage); + break; + case ELbsGetLastKnownPositionArea: + HandleGetLastKnownPositionAreaL(aMessage); + break; + case ELbsPosNotifyPositionUpdate: + LBS_RDEBUG("Client", "LBS", "NotifyPositionUpdate"); + HandleNotifyPositionUpdateL(aMessage); + break; + case ELbsPositionerCancelAsyncRequest: + LBS_RDEBUG("Client", "LBS", "CancelAsyncRequest"); + HandleCancelAsyncRequestL(aMessage); + break; + default: + DEBUG_TRACE("default switch case subsession ", __LINE__) + User::Leave(KErrNotSupported); + break; + } + } + +/** + * From MPosParameterObserver. + * + * Get the position quality requested by the client. + * + * @param aRequestedPosQuality The requested position quality. + */ +TInt CPosSubSession::GetRequiredPositionQuality(TPositionQuality& /*aRequestedPosQuality*/) const + { + DEBUG_TRACE("GetRequiredPositionQuality()", __LINE__) + + // Not implemented yet. + return KErrNotFound; + } + +/** + * From MPosParameterObserver. + * + * Get the earliest allowed time of an old position fix, based on the + * current max age set by the client. + * + * The PSY may save the result from the latest position request and + * return the same result in the next position request if the client + * says it's ok. Max age tells the PSY how old the stored position is + * allowed to be. If the stored position is too old or the PSY does not + * support max age, a normal positioning should be performed. + * + * @param aMaxAge On return, will contain the earliest allowed time of + * an old position fix. If no max age is defined aMaxAge will contain + * a time set to zero. + */ +void CPosSubSession::GetMaxAge(TTime& aMaxAge) const + { + DEBUG_TRACE("GetMaxAge()", __LINE__) + + if (iMaxUpdateAge != TTimeIntervalMicroSeconds(0)) + { + aMaxAge.UniversalTime(); + aMaxAge -= iMaxUpdateAge; + } + else + { + aMaxAge = TTime(0); + } + } + +/** + * From MPosParameterObserver. + * + * Checks if the client allows a partial position update. + * + * A partial update result does not need to contain all parameters. The + * only mandatory parameters are latitude, longitude and time of fix. + * Everything else is optional. + * + * If a partial update is returned to the client in a + * NotifyPositionUpdate() call, the completion code must be set to + * KPositionPartialUpdate. + * + * @return ETrue if partial position updates are allowed, otherwise + * EFalse. + */ +TBool CPosSubSession::IsPartialUpdateAllowed() const + { + DEBUG_TRACE("IsPartialUpdateAllowed()", __LINE__) + return iAcceptPartialUpdates; + } + +/** + * Called when a change has occurred in location settings db. + * @param aEvent Event information + */ +void CPosSubSession::HandleSettingsChangeL(TPosModulesEvent aEvent) + { + __ASSERT_DEBUG(iPositionRequest, DebugPanic(EPosServerPanicGeneralInconsistency)); + iPositionRequest->HandleSettingsChangeL(aEvent); + } + +/** + * Called when the server class is shutting down. + */ +void CPosSubSession::NotifyServerShutdown() + { + DEBUG_TRACE("NotifyServerShutdown", __LINE__) + + iPositionRequest->NotifyServerShutdown(); + } + +void CPosSubSession::HandleSetRequestorL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerSetSingleRequestor", __LINE__) + + // Destroy previously set requestors before any leaving code is called. + // If this method leaves, the requestor array must be empty so any + // subsequent call to NotifyPositionUpdate returns KErrAccessDenied. + iRequestors.ResetAndDestroy(); + + TPckgBuf requestorType; + User::LeaveIfError(Global::Read(aMessage, KParamRequestorType, requestorType)); + + // the requestor must be a service + if (requestorType() != CRequestor::ERequestorService) + { + User::Leave(KErrArgument); + } + + TPckgBuf requestorFormat; + User::LeaveIfError(Global::Read(aMessage, KParamRequestorFormat, requestorFormat)); + + HBufC* data = Global::CopyClientBufferLC(aMessage, KParamRequestorData); + + CRequestor* requestor = CRequestor::NewLC(requestorType(), requestorFormat(), *data); + ValidateRequestorL(requestor); + iRequestors.Append(requestor); // takes ownership + CleanupStack::Pop(requestor); + + iPositionRequest->NewTrackingSessionIfTracking(); + RequestComplete(aMessage, KErrNone); + + CleanupStack::PopAndDestroy(data); + } + +void CPosSubSession::HandleSetRequestorStackL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerSetMultipleRequestors", __LINE__) + + // Destroy previously set requestors before any leaving code is called. + iRequestors.ResetAndDestroy(); + + HBufC8* buf = Global::CopyClientBuffer8LC(aMessage, KParamRequestorStack); + RDesReadStream stream(*buf); + + iRequestors.InternalizeL(stream); + + CleanupStack::PopAndDestroy(buf); + + // If this method leaves, the requestor array must be empty so any + // subsequent call to NotifyPositionUpdate returns KErrAccessDenied. + TCleanupItem cleanup(ResetAndDestroyRRequestorStack, &iRequestors); + CleanupStack::PushL(cleanup); + + // Last requestor must be a service + if (iRequestors.Count() > 0) + { + CRequestor* last = iRequestors[iRequestors.Count() - 1]; + if (last->RequestorType() != CRequestor::ERequestorService) + { + User::Leave(KErrArgument); + } + } + else + { + User::Leave(KErrArgument); + } + + // validate them all + for (TInt i = 0; i < iRequestors.Count(); i++) + { + ValidateRequestorL(iRequestors[i]); + } + + CleanupStack::Pop(&iRequestors); + + iPositionRequest->NewTrackingSessionIfTracking(); + RequestComplete(aMessage, KErrNone); + } + +void CPosSubSession::HandleSetUpdateOptionsL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerSetUpdateOptions", __LINE__) + + HBufC8* optionsBuf = Global::CopyClientBuffer8LC(aMessage, KParamUpdateOptions); + TUint bufferSize = optionsBuf->Size(); + + TPositionUpdateOptionsBase& optionsBase = reinterpret_cast + (const_cast(*optionsBuf->Ptr())); + + // Check update options. Leaves if not accepted values. + + Global::ValidatePositionClassBufferL(optionsBase, optionsBuf->Des()); + Global::ValidatePositionClassTypeL(optionsBase, EPositionUpdateOptionsClass); + + TPositionUpdateOptions& options = + static_cast(optionsBase); + + if ((optionsBase.UpdateTimeOut().Int64() > 0) && + (optionsBase.UpdateInterval() >= optionsBase.UpdateTimeOut())) + { + User::Leave(KErrArgument); + } + + // Max age must be less than the update interval if both are set. + if (optionsBase.MaxUpdateAge().Int64() != 0 && + optionsBase.UpdateInterval().Int64() != 0 && + optionsBase.MaxUpdateAge() >= optionsBase.UpdateInterval()) + { + User::Leave(KErrArgument); + } + + iTracking = (optionsBase.UpdateInterval().Int64() != 0); + iMaxUpdateAge = optionsBase.MaxUpdateAge(); + iAcceptPartialUpdates = options.AcceptPartialUpdates(); + iUpdateTimeOut = optionsBase.UpdateTimeOut(); + + if(iUpdateTimeOut==0 && iPsyDefaultUpdateTimeOut>0) + { + optionsBase.SetUpdateTimeOut(iPsyDefaultUpdateTimeOut); + } + + iPositionRequest->SetUpdateOptions(optionsBase); + + CleanupStack::PopAndDestroy(optionsBuf); + RequestComplete(aMessage, KErrNone); + } + +void CPosSubSession::HandleGetUpdateOptionsL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerGetUpdateOptions", __LINE__) + + HBufC8* optionsBuf = Global::CopyClientBuffer8LC(aMessage, KParamUpdateOptions); + TUint bufferSize = optionsBuf->Size(); + + TPositionUpdateOptionsBase& optionsBase = reinterpret_cast + (const_cast(*optionsBuf->Ptr())); + + Global::ValidatePositionClassBufferL(optionsBase, optionsBuf->Des()); + Global::ValidatePositionClassTypeL(optionsBase, EPositionUpdateOptionsClass); + + TPositionUpdateOptions& options = static_cast(optionsBase); + + iPositionRequest->GetUpdateOptions(optionsBase); + optionsBase.SetMaxUpdateAge(iMaxUpdateAge); + options.SetAcceptPartialUpdates(iAcceptPartialUpdates); + optionsBase.SetUpdateTimeOut(iUpdateTimeOut); + + User::LeaveIfError(Global::Write(aMessage, KParamUpdateOptions, *optionsBuf)); + CleanupStack::PopAndDestroy(optionsBuf); + RequestComplete(aMessage, KErrNone); + } + +void CPosSubSession::HandleGetLastKnownPositionL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerGetLastKnownPosition", __LINE__) + + if (aMessage.Int1() != EPositionInfoClass) + { + User::Leave(KErrArgument); + } + + if ( aMessage.Int2() < sizeof(TPositionInfo) ) + { + User::Leave(KErrArgument); + } + + // Request the last known postion area from the CPosLocMonitorReqHandlerHub + iLocMonitorReqHandlerHub->GetLastKnownPosReqL(aMessage); + } + +/* Check that a Self-locate is allowed, given the current network roaming status +*/ +TBool CPosSubSession::IsSelfLocateEnabled() + { + DEBUG_TRACE("CPositionerSubSession::IsSelfLocateEnabled", __LINE__); + __ASSERT_DEBUG((iAdmin != NULL) && (iLocationManagementSupported != EFalse), DebugPanic(EPosServerPanicGeneralInconsistency)); + + TBool selfLocateAllowed(EFalse); + CLbsAdmin::TSelfLocateService serviceStatus(CLbsAdmin::ESelfLocateOff); + RLbsNetworkRegistrationStatus::TLbsNetworkRegistrationStatus netRegStatus(RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown); + + // Read the current network registration status + TInt err = iNetRegStatus.GetNetworkRegistrationStatus(netRegStatus); + if (err == KErrNone) + { + // Read the appropriate admin setting + switch (netRegStatus) + { + case RLbsNetworkRegistrationStatus::ERegisteredHomeNetwork: + { + err = iAdmin->Get(KLbsSettingHomeSelfLocate, serviceStatus); + break; + } + case RLbsNetworkRegistrationStatus::ERegisteredRoamingNetwork: + { + err = iAdmin->Get(KLbsSettingRoamingSelfLocate, serviceStatus); + break; + } + case RLbsNetworkRegistrationStatus::ENotRegistered: + { + err = iAdmin->Get(KLbsSettingRoamingSelfLocate, serviceStatus); + if(!err && serviceStatus == CLbsAdmin::ESelfLocateOff) + { + // in the case of notregistered we allow selflocate if *either* home or roaming setting is on: + err = iAdmin->Get(KLbsSettingHomeSelfLocate, serviceStatus); + } + } + break; + case RLbsNetworkRegistrationStatus::ENetworkRegistrationUnknown: + default: + { + serviceStatus = CLbsAdmin::ESelfLocateOff; + break; + } + } + } + + // Check to see if Self Locate is allowed + if (err == KErrNone + && serviceStatus == CLbsAdmin::ESelfLocateOn) + { + selfLocateAllowed = ETrue; + } + + return selfLocateAllowed; + } + +void CPosSubSession::HandleNotifyPositionUpdateL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerNotifyPositionUpdate", __LINE__) + + // Request cannot be made if one is already in progress + // + if (iPositionRequest->IsActive()) + { + aMessage.Panic(KPosClientFault, EPositionDuplicateRequest); + iPositionRequest->Cancel(); + return; + } + else if (iLocationManagementSupported && !IsSelfLocateEnabled()) + { + LBS_RDEBUG_ARGTEXT("LBS", "Client", "RunL", "KErrAccessDenied"); + aMessage.Complete(KErrAccessDenied); + return; + } + + // Initiate the request + iPositionRequest->MakeRequestL(aMessage); + } + +void CPosSubSession::HandleGetLastKnownPositionAreaL(const RMessage2& aMessage) + { + DEBUG_TRACE("ELbsGetLastKnownPositionArea", __LINE__) + + // Request the last known postion area from the CPosLocMonitorReqHandlerHub + iLocMonitorReqHandlerHub->GetLastKnownPosAreaReqL(aMessage); + + } + +void CPosSubSession::HandleGetLastKnownPositionAreaCancelL(const RMessage2& aMessage) + { + DEBUG_TRACE("ELbsGetLastKnownPositionAreaCancelL ", __LINE__) + + iLocMonitorReqHandlerHub->CancelGetLastKnownPosAreaReqL(aMessage); + + } + +void CPosSubSession::HandleNotifyPositionUpdateCancelL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerNotifyPositionUpdateCancel", __LINE__) + + if (!iPositionRequest->IsActive()) + { + User::Leave(KErrNotFound); + } + + iPositionRequest->Cancel(); + RequestComplete(aMessage, KErrNone); + } + +void CPosSubSession::HandleGetLastKnownPositionCancelL(const RMessage2& aMessage) + { + DEBUG_TRACE("EPositionerGetLastKnownPositionCancel", __LINE__) + iLocMonitorReqHandlerHub->CancelGetLastKnownPosReqL(aMessage); + + } + + +void CPosSubSession::HandleCancelAsyncRequestL(const RMessage2& aMessage) + { + switch (aMessage.Int0()) + { + case KGetLastKnownPositionSymbian: + case KGetLastKnownPositionVariant: + case ELbsGetLastKnownPosition: + HandleGetLastKnownPositionCancelL(aMessage); + break; + case KNotifyPositionUpdateSymbian: + case KNotifyPositionUpdateVariant: + case ELbsPosNotifyPositionUpdate: + HandleNotifyPositionUpdateCancelL(aMessage); + break; + case ELbsGetLastKnownPositionArea: + HandleGetLastKnownPositionAreaCancelL(aMessage); + break; + default: + User::Leave(KErrNotSupported); + break; + } + } + +void CPosSubSession::ValidateRequestorL(CRequestor* aRequestor) + { + // service is identified by application name + switch (aRequestor->RequestorType()) + { + case CRequestor::ERequestorService: + break; + case CRequestor::ERequestorContact: + if (aRequestor->RequestorFormat() == CRequestor::EFormatApplication) + { + User::Leave(KErrArgument); + } + break; + default: + User::Leave(KErrArgument); // service or contact is required + break; + } + + switch (aRequestor->RequestorFormat()) + { + case CRequestor::EFormatApplication: + case CRequestor::EFormatTelephone: + case CRequestor::EFormatUrl: + case CRequestor::EFormatMail: + break; + default: + User::Leave(KErrArgument); // Unknown or other + break; + } + } + +void CPosSubSession::RequestComplete(const RMessage2& aMessage, TInt aCompleteCode) + { + if (!aMessage.IsNull()) + { + aMessage.Complete(aCompleteCode); + } + } + +void CPosSubSession::GetUpdateTimeOut(TTimeIntervalMicroSeconds& aUpdateTimeOut) const + { + if(iUpdateTimeOut==0) + { + aUpdateTimeOut = iPsyDefaultUpdateTimeOut; + } + else + { + aUpdateTimeOut = iUpdateTimeOut; + } + } + +void CPosSubSession::SetPsyDefaultUpdateTimeOut(const TTimeIntervalMicroSeconds& aUpdateTimeOut) + { + iPsyDefaultUpdateTimeOut = aUpdateTimeOut; + + if(iPositionRequest) //It can be zero if this method is called back from CPosSubSession::ConctructL + { + TPositionUpdateOptions updateOptions; + iPositionRequest->GetUpdateOptions(updateOptions); + if(iUpdateTimeOut==0) + { + updateOptions.SetUpdateTimeOut(iPsyDefaultUpdateTimeOut); + iPositionRequest->SetUpdateOptions(updateOptions); + } + } + } + +void CPosSubSession::ExtendUpdateTimeOut(const TTimeIntervalMicroSeconds& aAdditionalTime) + { + iPositionRequest->ExtendUpdateTimeOut(aAdditionalTime); + } + + +