--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/locationrequestmgmt/locationserver/src/EPos_CPositionRequest.cpp Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,730 @@
+// 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 <e32base.h>
+#include <lbspositioninfo.h>
+#include <lbs/epos_cpositioner.h>
+#include <lbs/epos_cposmodules.h>
+#include <lbs/epos_mposmodulesobserver.h>
+#include "lbsdevloggermacros.h"
+#include "EPos_ServerPanic.h"
+#include "EPos_Global.h"
+#include "EPos_CPosCallbackTimer.h"
+#include "EPos_CPositionRequest.h"
+#include "epos_cposmodulessettings.h"
+
+//TODO Verify
+#include "EPos_CPosLocMonitorReqHandlerHub.h"
+
+
+
+// CONSTANTS
+#ifdef _DEBUG
+_LIT(KTraceFileName, "EPos_CPositionRequest.cpp");
+#endif
+
+const TInt KParamPositionInfo = 0;
+
+// ================= LOCAL FUNCTIONS ========================
+
+void CancelTimerCleanup(TAny* aTimer)
+ {
+ (static_cast<CPosCallbackTimer*>(aTimer))->Cancel();
+ }
+
+inline TPositionInfoBase& PositionInfoBase(HBufC8* aBuffer)
+ {
+ return reinterpret_cast<TPositionInfoBase&>
+ (const_cast<TUint8&>(*aBuffer->Ptr()));
+ }
+inline TPositionInfo& PositionInfo(HBufC8* aBuffer)
+ {
+ return reinterpret_cast<TPositionInfo&>
+ (const_cast<TUint8&>(*aBuffer->Ptr()));
+ }
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CPositionRequest::CPositionRequest(
+ CPosModuleSettings& aModuleSettings,
+ CPosLocMonitorReqHandlerHub& aLocMonitorReqHandlerHub,
+ TProxyPositionerConstructParams& aPositionerParams,
+ TBool aIsProxy)
+:
+ CActive(EPriorityStandard),
+ iRequestPhase(EPosReqInactive),
+ iPositionerParams(aPositionerParams),
+ iHasProxyPositioner(aIsProxy),
+ iLocMonitorReqHandler(aLocMonitorReqHandlerHub),
+ iModuleSettings(aModuleSettings)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+// EPOC default constructor can leave.
+void CPositionRequest::ConstructL()
+ {
+ TCallBack timeoutCallBack(HandleTimeOut, this);
+ iTimeoutTimer = CPosCallbackTimer::NewL(timeoutCallBack);
+
+ TCallBack trackingCallBack(TrackingCallback, this);
+ iTrackingTimer = CPosCallbackTimer::NewL(trackingCallBack);
+
+ iModuleSettings.PosModules().GetModuleInfoL(
+ iPositionerParams.iImplementationUid,
+ iModuleInfo);
+
+ if (!iModuleInfo.IsAvailable())
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ LoadPositionerL();
+ }
+
+/**
+ * Two-phased constructor.
+ *
+ * @param aModules Location Settings reference
+ * @param aLocMonitorReqHandlerHub The hub for requests to the location monitor.
+ * @param aPositionerParams contruction parameters needed when creating
+ * positioner.
+ * @param aIsProxy ETrue if aImplementationUid represents a proxy PSY,
+ * EFalse otherwise.
+ */
+CPositionRequest* CPositionRequest::NewL(
+ CPosModuleSettings& aModuleSettings,
+ CPosLocMonitorReqHandlerHub& aLocMonitorReqHandlerHub,
+ TProxyPositionerConstructParams& aPositionerParams,
+ TBool aIsProxy)
+ {
+ CPositionRequest* self = new (ELeave) CPositionRequest(
+ aModuleSettings,
+ aLocMonitorReqHandlerHub,
+ aPositionerParams,
+ aIsProxy);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+ * Destructor.
+ */
+CPositionRequest::~CPositionRequest()
+ {
+ // Panic client if request is outstanding
+ if (IsActive())
+ {
+ iMessage.Panic(KPosClientFault, EPositionRequestsNotCancelled);
+ }
+ Cancel();
+ if (iTrackingState == EPosTracking)
+ {
+ StopTracking();
+ }
+ delete iTrackingTimer;
+ delete iPositionBuffer;
+ delete iTimeoutTimer;
+ delete iPositioner;
+ }
+
+/**
+ * Starts a position request cycle. Should only be called when PSY is
+ * enabled.
+ * @param aMessage the request message from the client
+ */
+void CPositionRequest::MakeRequestL(const RMessage2& aMessage)
+ {
+ if (!iModuleInfo.IsAvailable())
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ __ASSERT_DEBUG(iPositioner, DebugPanic(EPosServerPanicPositionerNotInitialized));
+
+ iMessage = aMessage; // Store parameter here in case of leave.
+
+ // Clear previous position data
+ delete iPositionBuffer;
+ iPositionBuffer = NULL;
+
+ HBufC8* clientBuf = Global::CopyClientBuffer8LC(aMessage, KParamPositionInfo);
+ CleanupStack::Pop(clientBuf);
+ iPositionBuffer = clientBuf;
+
+ TPositionInfoBase& infoBase = PositionInfoBase(iPositionBuffer);
+ TUint32 classType = infoBase.PositionClassType();
+
+ TUint32 classesSupported = iModuleInfo.ClassesSupported(EPositionInfoFamily);
+
+ // Check that classtype is supported and is of type TPositionInfo
+ if ((classType != (classType & classesSupported)) ||
+ !(classType & EPositionInfoClass))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Set ModuleId to KNullId to be able to verify that Id is set by PSY.
+ infoBase.SetModuleId(KNullUid);
+
+ CleanupStack::PushL(TCleanupItem(CancelTimerCleanup, iTimeoutTimer));
+
+ // Start timer if necessary
+ if (iTimeOut.Int64() > 0)
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::MakeRequestL() Start Timeout Timer");
+ iTimeoutTimer->StartTimer(iTimeOut);
+ }
+
+ LBS_RDEBUG_VAR_INT("CPositionRequest::MakeRequestL() iTrackingState", iTrackingState);
+ switch (iTrackingState)
+ {
+ case EPosNoTracking:
+ case EPosFirstTrackingRequest:
+ StartPositionDataRequestPhase();
+ break;
+
+ case EPosTracking:
+ StartTrackingTimerWaitPhase();
+ break;
+
+ case EPosStopTracking:
+ // This must have been handled by Cancel or RunL
+ default:
+ DebugPanic(EPosServerPanicTrackingInconsistency);
+ }
+
+ CleanupStack::Pop(iTimeoutTimer);
+ }
+
+/**
+ * Set the TPositionUpdateOptions object.
+ *
+ * When this class is constructed, the TPositionUpdateOptions object
+ * is constructed using default constructor with no parameters.
+ *
+ * @param aOptions The update options from the client.
+ */
+void CPositionRequest::SetUpdateOptions(
+ const TPositionUpdateOptionsBase& aOptions)
+ {
+ iTimeOut = aOptions.UpdateTimeOut();
+ TTimeIntervalMicroSeconds newInterval = aOptions.UpdateInterval();
+ TTimeIntervalMicroSeconds oldInterval = iTrackingUpdateInterval;
+
+ if (newInterval != iTrackingUpdateInterval)
+ {
+ iTrackingUpdateInterval = newInterval;
+
+ if (newInterval == 0) // "stop periodic updates"
+ {
+ switch (iTrackingState)
+ {
+ case EPosFirstTrackingRequest:
+ iTrackingState = EPosNoTracking;
+ break;
+
+ case EPosTracking:
+ if (!IsActive())
+ {
+ // can stop it right now
+ StopTracking();
+ }
+ else
+ {
+ // mark to stop later
+ iTrackingState = EPosStopTracking;
+ }
+ break;
+
+ case EPosNoTracking:
+ case EPosStopTracking:
+ break;
+ default:
+ DebugPanic(EPosServerPanicTrackingInconsistency);
+ break;
+ }
+ }
+ else if (oldInterval != 0) // "use another update interval"
+ {
+ if (iRequestPhase == EPosReqInactive)
+ {
+ TInt err;
+ TRAP(err, RestartTrackingL());
+ }
+ else
+ {
+ // can't affect outstanding request
+ // postpone until request is completed
+ // it will be handled by RunL or DoCancel
+ // via HandleTrackingStateL
+ iNewTrackingInterval = ETrue;
+ }
+ }
+ else
+ {
+ // oldInterval == 0
+ // newInterval != 0
+ // it means - "start periodic updates"
+ iTrackingState = EPosFirstTrackingRequest;
+ }
+ }
+ }
+
+/**
+ * Get the TPositionUpdateOptions object.
+ * @param aOptions The TPositionUpdateOptions object.
+ */
+void CPositionRequest::GetUpdateOptions(
+ TPositionUpdateOptionsBase& aOptions) const
+ {
+ aOptions.SetUpdateTimeOut(iTimeOut);
+ aOptions.SetUpdateInterval(iTrackingUpdateInterval);
+ }
+
+/**
+ * Stops current tracking session
+ */
+void CPositionRequest::NewTrackingSessionIfTracking()
+ {
+ /* Requestor has been changed. Call Privacy Server. */
+ }
+
+/**
+ * Called when changes in locations settings occur.
+ * @param aEvent Event information
+ */
+void CPositionRequest::HandleSettingsChangeL(TPosModulesEvent aEvent)
+ {
+ if (aEvent.iModuleId != iModuleInfo.ModuleId())
+ {
+ return;
+ }
+
+ switch (aEvent.iType)
+ {
+ case EPosModulesEventAvailabilityChanged:
+ case EPosModulesEventModuleInstalled:
+ iModuleSettings.PosModules().GetModuleInfoL(
+ iModuleInfo.ModuleId(),
+ iModuleInfo);
+ break;
+ case EPosModulesEventModuleRemoved:
+ iModuleInfo.SetIsAvailable(EFalse);
+ break;
+ default:
+ return;
+ }
+
+ if (!iModuleInfo.IsAvailable())
+ {
+ if (IsActive())
+ {
+ CompleteClient(KErrNotFound);
+ Cancel();
+ }
+
+ // Unuse positioner and unload it
+ if (iTrackingState == EPosTracking)
+ {
+ StopPsyTracking();
+ }
+ delete iPositioner;
+ iPositioner = NULL;
+ }
+ else if (!iPositioner)
+ {
+ // psy is re-enabled after being disabled
+ LoadPositionerL();
+ if (iTrackingState == EPosTracking)
+ {
+ StartPsyTrackingL();
+ }
+ }
+ else
+ {
+ // shouldn't happen, but if it does, ignore it
+ }
+ }
+
+/**
+ * Called when the server class is shutting down.
+ */
+void CPositionRequest::NotifyServerShutdown()
+ {
+ if (IsActive())
+ {
+ DEBUG_TRACE("CPositionRequest::NotifyServerShutdown() with active request", __LINE__)
+ CompleteClient(KErrServerTerminated);
+ Cancel();
+ }
+
+ if (iTrackingState == EPosTracking)
+ {
+ StopTracking();
+ }
+ delete iPositioner;
+ iPositioner = NULL;
+ }
+
+/**
+ * From CActive
+ */
+void CPositionRequest::RunL()
+ {
+ LBS_RDEBUG_VAR_INT("CPositionRequest::RunL() iRequestPhase", iRequestPhase);
+ TInt err = iStatus.Int();
+ switch (iRequestPhase)
+ {
+ case EPosReqPositionRequest:
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::RunL() EPosReqPositionRequest");
+ // Position request finished. Cancel timer.
+ iTimeoutTimer->Cancel();
+ iRequestPhase = EPosReqInactive;
+
+ CompleteRequest(err);
+
+ HandleTrackingStateL(); // don't care if it leaves
+ break;
+ }
+
+ case EPosWaitForTracking:
+ StartPositionDataRequestPhase();
+ break;
+
+ default :
+ DEBUG_TRACE("CPositionRequest::RunL() panicing", __LINE__)
+ DebugPanic(EPosServerPanicRequestInconsistency);
+ }
+ }
+
+/**
+ * From CActive
+ */
+TInt CPositionRequest::RunError(TInt /*aError*/)
+ {
+ // Happens only if HandleTrackingStateL leaves
+ // which in turn means that StartTrackingL leaved somewhere
+ // As request is already completed, just ignore the error
+ return KErrNone;
+ }
+
+/**
+ * From CActive
+ */
+void CPositionRequest::DoCancel()
+ {
+ LBS_RDEBUG_VAR_INT("CPositionRequest::DoCancel() iRequestPhase", iRequestPhase);
+ iTimeoutTimer->Cancel();
+
+ switch (iRequestPhase)
+ {
+ case EPosReqPositionRequest:
+ {
+ __ASSERT_DEBUG(iPositioner, DebugPanic(EPosServerPanicPositionerNotInitialized));
+ DEBUG_TRACE("calling CPositioner::CancelNotifyPositionUpdate()", __LINE__)
+ if(iRequestTimedOut)
+ {
+ iPositioner->CancelNotifyPositionUpdate(KErrTimedOut);
+ }
+ else
+ {
+ iPositioner->CancelNotifyPositionUpdate();
+ }
+ break;
+ }
+ case EPosWaitForTracking:
+ CompleteSelf(KErrCancel);
+ break;
+
+ default:
+ DEBUG_TRACE("CPositionRequest::DoCancel() panicing", __LINE__)
+ DebugPanic(EPosServerPanicRequestInconsistency);
+ }
+
+ TInt err;
+ if (iRequestTimedOut)
+ {
+ iRequestTimedOut = EFalse;
+ CompleteClient(KErrTimedOut);
+ TRAP(err, HandleTrackingStateL());
+ }
+ else
+ {
+ CompleteClient(KErrCancel);
+
+ // Handle Tracking State
+ if (iTrackingState == EPosStopTracking)
+ {
+ StopTracking();
+ }
+ }
+
+ iRequestPhase = EPosReqInactive;
+ }
+
+
+void CPositionRequest::CompleteSelf(TInt aReason)
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, aReason);
+ }
+
+void CPositionRequest::CompleteClient(TInt aReason)
+ {
+ if (!iMessage.IsNull())
+ {
+ LBS_RDEBUG_ARGINT("LBS","Client", "RunL", aReason);
+ iMessage.Complete(aReason);
+ }
+ }
+
+void CPositionRequest::CompleteRequest(TInt aReason)
+ {
+ // Return fix to the client
+ if (aReason == KErrNone || aReason == KPositionPartialUpdate)
+ {
+ TInt err = PackPositionData();
+ // err - client cannot receive result data
+ CompleteClient((err != KErrNone) ? err : aReason);
+
+ // Save current fix to LastKnownPosition handler
+ // partial updates are not stored
+ if ( aReason == KErrNone )
+ {
+ SaveAsLastKnownPosition();
+ }
+ }
+ else
+ {
+ CompleteClient(aReason);
+ }
+ }
+
+void CPositionRequest::StartPositionDataRequestPhase()
+ {
+ LBS_RDEBUG_VAR_INT("CPositionRequest::StartPositionDataRequestPhase() iRequestPhase", iRequestPhase);
+
+ __ASSERT_DEBUG(iPositioner,
+ DebugPanic(EPosServerPanicPositionerNotInitialized));
+
+ iReqStartTime.UniversalTime();
+
+ TPositionInfo& info = PositionInfo(iPositionBuffer);
+
+ // Set datum type to WGS84
+ TPosition position;
+ info.GetPosition(position);
+ position.SetDatum(KPositionDatumWgs84);
+ info.SetPosition(position);
+
+ TPositionInfoBase& infoBase = reinterpret_cast<TPositionInfoBase&>(info);
+
+ // issue request to psy
+ DEBUG_TRACE("calling CPositioner::NotifyPositionUpdate()", __LINE__)
+
+ iStatus = KRequestPending;
+ iPositioner->NotifyPositionUpdate(infoBase, iStatus);
+
+ iRequestPhase = EPosReqPositionRequest;
+ SetActive();
+ }
+
+void CPositionRequest::StartTrackingTimerWaitPhase()
+{
+ LBS_RDEBUG_VAR_INT("CPositionRequest::StartTrackingTimerWaitPhase() iRequestPhase", iRequestPhase);
+ iRequestPhase = EPosWaitForTracking;
+ iStatus = KRequestPending;
+ SetActive();
+}
+
+TInt CPositionRequest::PackPositionData()
+ {
+ TPositionInfo& info = PositionInfo(iPositionBuffer);
+
+ // Verify that ModuleId, set by PSY, is correct if using specific PSY.
+ // If a proxy PSY is used, the proxy is responsible for verifying UID.
+ if (!iHasProxyPositioner &&
+ info.ModuleId() != iPositionerParams.iImplementationUid)
+ {
+ return KErrGeneral;
+ }
+
+ // Check that datum type still is WGS84
+ TPosition position;
+ info.GetPosition(position);
+ if (position.Datum() != KPositionDatumWgs84)
+ {
+ return KErrNotSupported;
+ }
+
+ TPtr8 ptrToBuffer = iPositionBuffer->Des();
+ return Global::Write(iMessage, KParamPositionInfo, ptrToBuffer);
+ }
+
+void CPositionRequest::SaveAsLastKnownPosition()
+ {
+ TPosition pos;
+ TPositionInfo& positionInfo = PositionInfo(iPositionBuffer);
+ positionInfo.GetPosition(pos);
+
+ // Don't set last known position if the position request is in the past. //TODO check if this is required
+ if (iReqStartTime <= pos.Time())
+ {
+ iLocMonitorReqHandler.SetPositionInfo(positionInfo);
+ }
+ }
+
+TInt CPositionRequest::HandleTimeOut(TAny* aPositionRequest)
+ {
+ CPositionRequest* self =
+ reinterpret_cast<CPositionRequest*>(aPositionRequest);
+
+ LBS_RDEBUG_VAR_INT("CPositionRequest::HandleTimeOut() iRequestPhase", self->iRequestPhase);
+ DEBUG_TRACE("CPositionRequest::HandleTimeOut()", __LINE__)
+ __ASSERT_DEBUG(self->iRequestPhase == EPosReqPositionRequest || self->iRequestPhase == EPosWaitForTracking,
+ DebugPanic(EPosServerPanicRequestInconsistency));
+
+ self->iRequestTimedOut = ETrue;
+ self->Cancel();
+
+ return KErrNone;
+ }
+
+TInt CPositionRequest::TrackingCallback(TAny* aPositionRequest)
+ {
+ CPositionRequest* self =
+ reinterpret_cast<CPositionRequest*>(aPositionRequest);
+
+ // continue tracking timer
+ if (self->iTrackingState == EPosTracking)
+ {
+ self->ContinueTrackingTimer();
+ }
+
+ if (self->iRequestPhase == EPosWaitForTracking)
+ {
+ // This is the normal case. The client's request was delayed
+ // by the update interval.
+ // Complete tracking timer waiting and go next stage
+ self->CompleteSelf(KErrNone);
+ }
+
+ return KErrNone;
+ }
+
+void CPositionRequest::HandleTrackingStateL()
+ {
+ switch (iTrackingState)
+ {
+ case EPosNoTracking:
+ break;
+
+ case EPosFirstTrackingRequest:
+ // start internal tracking
+ iTrackingState = EPosTracking;
+ ContinueTrackingTimer();
+
+ StartPsyTrackingL();
+ break;
+
+ case EPosTracking:
+ // if tracking interval was changed
+ if (iNewTrackingInterval)
+ {
+ RestartTrackingL();
+ }
+ break;
+
+ case EPosStopTracking:
+ StopTracking();
+ break;
+
+ default:
+ DebugPanic(EPosServerPanicTrackingInconsistency);
+ }
+ }
+
+void CPositionRequest::StartPsyTrackingL()
+ {
+ __ASSERT_DEBUG(iPositioner, DebugPanic(EPosServerPanicPositionerNotInitialized));
+
+ iNewTrackingInterval = EFalse;
+
+ DEBUG_TRACE("calling CPositioner::TrackingOverridden()", __LINE__)
+ if (iPositioner->TrackingOverridden())
+ {
+ DEBUG_TRACE("calling CPositioner::StartTrackingL()", __LINE__)
+ iPositioner->StartTrackingL(iTrackingUpdateInterval);
+ iPositionerTrackingStarted = ETrue;
+ }
+ }
+
+void CPositionRequest::RestartTrackingL()
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::RestartTrackingL()");
+ iTrackingTimer->Cancel();
+ StopPsyTracking();
+ ContinueTrackingTimer();
+ StartPsyTrackingL();
+ }
+
+void CPositionRequest::StopTracking()
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::StopTracking()");
+ iTrackingTimer->Cancel();
+ iTrackingState = EPosNoTracking;
+
+ StopPsyTracking();
+ }
+
+void CPositionRequest::StopPsyTracking()
+ {
+ if (iPositioner && iPositionerTrackingStarted)
+ {
+ DEBUG_TRACE("calling CPositioner::StopTracking()", __LINE__)
+ iPositioner->StopTracking();
+ iPositionerTrackingStarted = EFalse;
+ }
+ }
+
+void CPositionRequest::ContinueTrackingTimer()
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::ContinueTrackingTimer()");
+ iTrackingTimer->StartTimer(iTrackingUpdateInterval);
+ }
+
+void CPositionRequest::LoadPositionerL()
+ {
+ iPositioner = CPositioner::NewL(&iPositionerParams);
+ iPositionerTrackingStarted = EFalse;
+ }
+
+void CPositionRequest::ExtendUpdateTimeOut(const TTimeIntervalMicroSeconds& aAdditionalTime)
+ {
+ LBS_RDEBUG_INFO("CPositionRequest::ExtendUpdateTimeOut()");
+ iTimeoutTimer->ExtendTimeout(aAdditionalTime);
+ }
+
+// End of File