diff -r 000000000000 -r 9cfd9a3ee49c locationrequestmgmt/locationserver/src/EPos_CPosModulesStatus.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/locationrequestmgmt/locationserver/src/EPos_CPosModulesStatus.cpp Tue Feb 02 01:50:39 2010 +0200 @@ -0,0 +1,749 @@ +// 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 +#include +#include "epos_mposmodulestatuslistener.h" + +#include "EPos_CPosModulesStatus.h" +#include "EPos_Global.h" +#include "EPos_ServerPanic.h" + +// CONSTANTS +#ifdef _DEBUG +_LIT(KTraceFileName, "EPos_CPosModulesStatus.cpp"); +#endif + +const TInt KParamModuleStatusEvent = 0; +const TInt KParamModuleId = 1; + +const TTimeIntervalMicroSeconds32 KTimerInterval = 5000000; // microseconds +const TInt KSequenceNoStartValue = 1; + +const TInt KStatusInactive = TPositionModuleStatus::EDeviceInactive; +const TInt KStatusDisabled = TPositionModuleStatus::EDeviceDisabled; +const TInt KStatusError = TPositionModuleStatus::EDeviceError; + +const TInt KEventInstalled = TPositionModuleStatusEvent::ESystemModuleInstalled; +const TInt KEventRemoved = TPositionModuleStatusEvent::ESystemModuleRemoved; +const TInt KEventStatus = TPositionModuleStatusEvent::EEventDeviceStatus; +const TInt KEventSystem = TPositionModuleStatusEvent::EEventSystemModuleEvent; +const TInt KEventQuality = TPositionModuleStatusEvent::EEventDataQualityStatus; + + +// LOCAL FUNCTION PROTOTYPES +TBool MatchModuleStatus(const CPosModulesStatus::TPosModule& aFirst, const CPosModulesStatus::TPosModule& aSecond); + +TIdentityRelation moduleMatcher(MatchModuleStatus); + +TBool MatchSubscriber(const CPosModulesStatus::TPosSubscriber& aFirst, const CPosModulesStatus::TPosSubscriber& aSecond); + +TIdentityRelation subscriberMatcher(MatchSubscriber); + +TBool EventMatchesRequested(const TPositionModuleStatusEvent& aOccurredEvent, const CPosModulesStatus::TPosSubscriber& aSubscriber); + +// ==================== LOCAL FUNCTIONS ==================== + +TBool MatchModuleStatus(const CPosModulesStatus::TPosModule& aFirst, const CPosModulesStatus::TPosModule& aSecond) + { + return (aFirst.iModuleId == aSecond.iModuleId); + } + +TBool MatchSubscriber(const CPosModulesStatus::TPosSubscriber& aFirst, const CPosModulesStatus::TPosSubscriber& aSecond) + { + return (aFirst.iClient == aSecond.iClient); + } + +TBool EventMatchesRequested(const TPositionModuleStatusEvent& aOccurredEvent, const CPosModulesStatus::TPosSubscriber& aSubscriber) + { + // Does module id match? + if ((aSubscriber.iModuleId != KPositionNullModuleId) && + (aSubscriber.iModuleId != aOccurredEvent.ModuleId())) + { + return EFalse; + } + + // Does requested event match occurred event? + if (!(aSubscriber.iEvent.RequestedEvents() & + aOccurredEvent.OccurredEvents())) + { + return EFalse; + } + + return ETrue; + } + +// ================= MEMBER FUNCTIONS ======================= + +/** + * C++ default constructor. + */ +CPosModulesStatus::CPosModulesStatus( CPosModules& aModules, const TTimeIntervalMicroSeconds32& aTimerInterval) + : iModules(aModules), + iSequenceNo(KSequenceNoStartValue), + iTimerInterval(aTimerInterval) + { + } + +/** + * Symbian constructor + */ +void CPosModulesStatus::ConstructL() + { + CPosModuleIdList* idList = iModules.ModuleIdListLC(); + TInt count = idList->Count(); + for (TInt i = 0; i < count; i++) + { + // Set module id + TPosModule module; + module.iModuleId = (*idList)[i]; + + // Set device status + TPositionModuleInfo moduleInfo; + TRAPD(err, iModules.GetModuleInfoL((*idList)[i], moduleInfo)); + if (err == KErrNone) + { + module.iStatus.SetDeviceStatus( moduleInfo.IsAvailable() ? + KStatusInactive : KStatusDisabled); + } + else + { + module.iStatus.SetDeviceStatus(KStatusError); + } + + // Store module status + User::LeaveIfError(iModuleStatusArray.Append(module)); + } + CleanupStack::PopAndDestroy(idList); + + iTimer = CPeriodic::NewL(EPriorityLow); + } + +/** + * Two-phased constructor. + */ +CPosModulesStatus* CPosModulesStatus::NewL(CPosModules& aModules) + { + return NewL(aModules, KTimerInterval); + } + +/** + * Two-phased constructor. + */ +CPosModulesStatus* CPosModulesStatus::NewL(CPosModules& aModules, const TTimeIntervalMicroSeconds32& aTimerInterval) + { + CPosModulesStatus* self = new (ELeave) CPosModulesStatus(aModules, aTimerInterval); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** + * Destructor. + */ +CPosModulesStatus::~CPosModulesStatus() + { + iListenerArray.Close(); + iModuleStatusArray.Close(); + iSubscribers.Close(); + delete iTimer; + } + +/** + * From MPosModuleStatusManager + */ +void CPosModulesStatus::AddListenerL(MPosModuleStatusListener& aListener) + { + User::LeaveIfError( iListenerArray.Append( &aListener ) ); + } + +/** + * From MPosModuleStatusManager + */ +void CPosModulesStatus::RemoveListener(MPosModuleStatusListener& aListener) + { + TInt count = iListenerArray.Count(); + for ( TInt i = count-1; i >= 0; i-- ) + { + if ( iListenerArray[i] == &aListener ) + { + iListenerArray.Remove( i ); + } + } + } + + +/** + * From MPosModuleStatusManager + */ +TInt CPosModulesStatus::GetModuleStatus(const TPositionModuleId& aModuleId, TPositionModuleStatusBase& aStatus) const + { + if (!(aStatus.PositionClassType() == EPositionModuleStatusClass)) + { + return KErrNotSupported; + } + + // Set the module status + TPositionModuleStatus& status = + static_cast(aStatus); + + // Find our stored module status + TPosModule module; + module.iModuleId = aModuleId; + TInt index = iModuleStatusArray.Find(module, moduleMatcher); + if (index == KErrNotFound) + { + return KErrNotFound; + } + + TPosModule storedModule = iModuleStatusArray[index]; + + status.SetDeviceStatus(storedModule.iStatus.DeviceStatus()); + status.SetDataQualityStatus(storedModule.iStatus.DataQualityStatus()); + + return KErrNone; + } + +/** + * Requests for status change notification. + * + * @param aMessage The message that will be completed when the + * requested event occurs. The message also contains + * all the request information. + * @param aClient A pointer to the client that handles the request. + */ +void CPosModulesStatus::NotifyModuleStatusEventL(const RMessage2& aMessage, TAny* aClient) + { + TPositionModuleId id; + TPositionModuleStatusEvent event; + + ValidateRequestL(aMessage, id, event); + + TPosSubscriber subscriber; + subscriber.iClient = aClient; + + // Is the client previously known? + TInt index = iSubscribers.Find(subscriber, subscriberMatcher); + if (index == KErrNotFound) + { + subscriber.iToBeRemoved = EFalse; + subscriber.iHasRequest = ETrue; + subscriber.iMsg = aMessage; + subscriber.iModuleId = id; + subscriber.iEvent = event; + User::LeaveIfError(iSubscribers.Append(subscriber)); + } + else + { + TPosSubscriber& storedSubscriber = iSubscribers[index]; + if (storedSubscriber.iHasRequest) + { + iSubscribers.Remove(index); + aMessage.Panic(KPosClientFault, EPositionDuplicateRequest); + return; + } + storedSubscriber.iToBeRemoved = EFalse; + storedSubscriber.iMsg = aMessage; + storedSubscriber.iModuleId = id; + storedSubscriber.iEvent = event; + if (!HasValidEventsQueued(storedSubscriber)) + { + storedSubscriber.iHasRequest = ETrue; + } + } + } + +/** + * Cancels a requested status change notification. + * + * @param aClient A pointer to the client to cancel. + */ +void CPosModulesStatus::CancelNotifyModuleStatusEventL(TAny* aClient) + { + TPosSubscriber subscriber; + subscriber.iClient = aClient; + + TInt index = iSubscribers.Find(subscriber, subscriberMatcher); + if (index == KErrNotFound) + { + User::Leave(KErrNotFound); + } + + TPosSubscriber storedSubscriber = iSubscribers[index]; + + iSubscribers.Remove(index); + + if (!storedSubscriber.iHasRequest) + { + User::Leave(KErrNotFound); + } + + RequestComplete(storedSubscriber.iMsg, KErrCancel); + } + +/** + * This function is called by a session when it is closed. It panics the + * client if it has any open request. A request subscriber to the + * closing session is removed. + * + * @param aClient A pointer to the client to cancel. + */ +void CPosModulesStatus::NotifySessionClosed(TAny* aClient) + { + TPosSubscriber subscriber; + subscriber.iClient = aClient; + + TInt index = iSubscribers.Find(subscriber, subscriberMatcher); + if (index == KErrNotFound) + { + return; + } + + TPosSubscriber storedSubscriber = iSubscribers[index]; + + iSubscribers.Remove(index); + + if (storedSubscriber.iHasRequest) + { + storedSubscriber.iMsg.Panic(KPosClientFault, EPositionRequestsNotCancelled); + } + } + +/** + * Called when a change has been detected in the location settings. + * @param aEvent Event information + */ +void CPosModulesStatus::HandleSettingsChangeL(TPosModulesEvent aEvent) + { + DEBUG_TRACE("HandleSettingsChange", __LINE__) + + TPosModule module; + module.iModuleId = aEvent.iModuleId; + + TPositionModuleStatusEvent event; + event.SetModuleId(aEvent.iModuleId); + + switch (aEvent.iType) + { + case EPosModulesEventModuleInstalled: + { + module.iStatus.SetDeviceStatus(KStatusInactive); + module.iDeviceTimeStamp = iSequenceNo; + module.iDataQualityTimeStamp = iSequenceNo++; + + User::LeaveIfError(iModuleStatusArray.Append(module)); + + event.SetSystemModuleEvent(KEventInstalled); + event.SetOccurredEvents(KEventSystem | KEventStatus); + event.SetModuleStatus(module.iStatus); + break; + } + case EPosModulesEventModuleRemoved: + { + TInt pos = iModuleStatusArray.Find(module, moduleMatcher); + if (pos != KErrNotFound) + { + iModuleStatusArray.Remove(pos); + + event.SetSystemModuleEvent(KEventRemoved); + event.SetOccurredEvents(KEventSystem); + } + break; + } + case EPosModulesEventAvailabilityChanged: + { + TPositionModuleInfo moduleInfo; + iModules.GetModuleInfoL(aEvent.iModuleId, moduleInfo); + + TInt pos = iModuleStatusArray.Find(module, moduleMatcher); + if (pos != KErrNotFound) + { + TPosModule& storedModule = iModuleStatusArray[pos]; + + if (moduleInfo.IsAvailable() && + storedModule.iStatus.DeviceStatus() == KStatusDisabled) + { + storedModule.iStatus.SetDeviceStatus(KStatusInactive); + event.SetOccurredEvents(KEventStatus); + } + else if (!moduleInfo.IsAvailable() && + storedModule.iStatus.DeviceStatus() != KStatusDisabled) + { + storedModule.iStatus.SetDeviceStatus(KStatusDisabled); + event.SetOccurredEvents(KEventStatus); + } + else + { + } + + if (event.OccurredEvents()) + { + storedModule.iDeviceTimeStamp = iSequenceNo++; + event.SetModuleStatus(storedModule.iStatus); + } + } + + break; + } + + case EPosModulesEventVisibilityChanged: + case EPosModulesEventPrioritiesChanged: + case EPosModulesEventCostChanged: + break; + + default: + DebugPanic(EPosServerPanicUnexpectedEvent); + break; + } + + // Has any event occurred? + if (event.OccurredEvents()) + { + NotifySubscribers(event); + NotifyListeners( event ); + } + } + +/** + * From MPosStatusObserver. + * + * Reports that the positioner status has changed. + * + * @param aStatus The new status. + */ +void CPosModulesStatus::ReportStatus( + const TPositionModuleId& aImplementationUid, + const TPositionModuleStatus& aStatus) + { +#ifdef _DEBUG + _LIT(KTracePoint, "ReportStatus()"); + Global::Trace(KTracePoint, KTraceFileName, __LINE__); +#endif + + TPosModule module; + module.iModuleId = aImplementationUid; + TInt index = iModuleStatusArray.Find(module, moduleMatcher); + if (index == KErrNotFound) + { + // This should never happen if PSYs are implemented correctly. + // Ignore the event. + return; + } + + TPosModule& storedModule = iModuleStatusArray[index]; + TPositionModuleStatus::TDeviceStatus storedDeviceStatus = + storedModule.iStatus.DeviceStatus(); + if (storedDeviceStatus == KStatusDisabled) + { + // Ignore event if module is disabled + return; + } + + TPositionModuleStatusEvent event; + TPositionModuleStatus::TDeviceStatus newDeviceStatus = + aStatus.DeviceStatus(); + if (storedDeviceStatus != newDeviceStatus) + { + storedModule.iStatus.SetDeviceStatus(newDeviceStatus); + storedModule.iDeviceTimeStamp = iSequenceNo; + event.SetOccurredEvents(KEventStatus); + } + if (storedModule.iStatus.DataQualityStatus() != + aStatus.DataQualityStatus()) + { + storedModule.iStatus.SetDataQualityStatus(aStatus.DataQualityStatus()); + storedModule.iDataQualityTimeStamp = iSequenceNo; + event.SetOccurredEvents(KEventQuality | (event.OccurredEvents())); + } + + // Has any event occurred? + if (event.OccurredEvents()) + { + // In order to get the same time stamp on both device status and data + // quality status, the counter is not incremented until here. + iSequenceNo++; + event.SetModuleId(aImplementationUid); + event.SetModuleStatus(storedModule.iStatus); + NotifySubscribers(event); + NotifyListeners( event ); + } + } + +/** + * Validate request + */ +void CPosModulesStatus::ValidateRequestL( + const RMessage2& aMessage, + TPositionModuleId& aId, + TPositionModuleStatusEvent& aEvent) + { +DEBUG_TRACE("ValidateRequestL in", __LINE__); + HBufC8* buffer = Global::CopyClientBuffer8LC(aMessage, KParamModuleStatusEvent); + + // Read module status event + const TPositionModuleStatusEventBase* moduleStatusEventBase = + reinterpret_cast(buffer->Ptr()); + + Global::ValidatePositionClassBufferL(*moduleStatusEventBase, buffer->Des()); + Global::ValidatePositionClassTypeL(*moduleStatusEventBase, EPositionModuleStatusEventClass); + + CleanupStack::PopAndDestroy(buffer); + +DEBUG_TRACE("Reading event object", __LINE__); + // Event type is ok so store the client data + TPckg eventBuf(aEvent); + User::LeaveIfError(Global::Read(aMessage, KParamModuleStatusEvent, eventBuf)); + +DEBUG_TRACE("Reading module id", __LINE__); + // Unpack the module id + TPckg moduleId(aId); + User::LeaveIfError(Global::Read(aMessage, KParamModuleId, moduleId)); + + // Is module id valid? + if (aId != KPositionNullModuleId) + { + TPosModule module; + module.iModuleId = aId; + + TInt index = iModuleStatusArray.Find(module, moduleMatcher); + if (index == KErrNotFound) + { + User::Leave(KErrNotFound); + } + } +DEBUG_TRACE("ValidateRequestL out", __LINE__); + } + +/** + * Check if valid event queued + */ +TBool CPosModulesStatus::HasValidEventsQueued(TPosSubscriber& aSubscriber) + { + if (aSubscriber.iClientTimeStamp == (iSequenceNo - 1)) + { + // No event has occurred + return EFalse; + } + + if (aSubscriber.iModuleId != KPositionNullModuleId) + { + // Only one module needs to be checked + TPosModule module; + module.iModuleId = aSubscriber.iModuleId; + TInt index = iModuleStatusArray.Find(module, moduleMatcher); + TPosModule storedModule = iModuleStatusArray[index]; + + TPositionModuleStatusEvent event; + if ((aSubscriber.iEvent.RequestedEvents() & KEventStatus) && + (storedModule.iDeviceTimeStamp > aSubscriber.iClientTimeStamp)) + { + event.SetOccurredEvents(KEventStatus); + } + if ((aSubscriber.iEvent.RequestedEvents() & KEventQuality) && + (storedModule.iDataQualityTimeStamp > aSubscriber.iClientTimeStamp)) + { + event.SetOccurredEvents(KEventQuality | event.OccurredEvents()); + } + + if (event.OccurredEvents()) + { + aSubscriber.iClientTimeStamp = + Max(storedModule.iDeviceTimeStamp, + storedModule.iDataQualityTimeStamp); + + event.SetModuleId(storedModule.iModuleId); + event.SetModuleStatus(storedModule.iStatus); + + NotifyEventToSubscriber(event, aSubscriber); + + return ETrue; + } + + return EFalse; + } + + // Search all matching modules for lowest time stamp later than client + TInt lowestValidTimeStamp = iSequenceNo; + TPositionModuleStatusEvent lowestValidEvent; + TInt count = iModuleStatusArray.Count(); + for (TInt j = 0; j < count; j++) + { + TPosModule storedModule = iModuleStatusArray[j]; + + TPositionModuleStatusEvent event; + if ((aSubscriber.iEvent.RequestedEvents() & KEventStatus) && + (storedModule.iDeviceTimeStamp > aSubscriber.iClientTimeStamp) && + (storedModule.iDeviceTimeStamp < lowestValidTimeStamp)) + { + event.SetOccurredEvents(KEventStatus); + lowestValidTimeStamp = storedModule.iDeviceTimeStamp; + + // Check if data quality status change occurred at the same time + if ((aSubscriber.iEvent.RequestedEvents() & KEventQuality) && + (storedModule.iDataQualityTimeStamp == storedModule.iDeviceTimeStamp)) + { + event.SetOccurredEvents(KEventQuality | event.OccurredEvents()); + } + } + + if ((aSubscriber.iEvent.RequestedEvents() & KEventQuality) && + (storedModule.iDataQualityTimeStamp > aSubscriber.iClientTimeStamp) && + (storedModule.iDataQualityTimeStamp < lowestValidTimeStamp)) + { + event.SetOccurredEvents(KEventQuality); + lowestValidTimeStamp = storedModule.iDataQualityTimeStamp; + } + + if (event.OccurredEvents()) + { + lowestValidEvent = event; + + lowestValidEvent.SetModuleId(storedModule.iModuleId); + lowestValidEvent.SetModuleStatus(storedModule.iStatus); + } + } + + if (lowestValidEvent.OccurredEvents()) + { + aSubscriber.iClientTimeStamp = lowestValidTimeStamp; + + NotifyEventToSubscriber(lowestValidEvent, aSubscriber); + + return ETrue; + } + + return EFalse; + } + +/** + * Notify subscribers + */ +void CPosModulesStatus::NotifySubscribers( + TPositionModuleStatusEvent& aOccurredEvent) + { + TInt count = iSubscribers.Count(); + for (TInt i = 0; i < count; i++) + { + TPosSubscriber& subscriber = iSubscribers[i]; + if (subscriber.iHasRequest) + { + if (EventMatchesRequested(aOccurredEvent, subscriber)) + { + NotifyEventToSubscriber(aOccurredEvent, subscriber); + + subscriber.iClientTimeStamp = iSequenceNo++; + subscriber.iHasRequest = EFalse; + subscriber.iToBeRemoved = EFalse; + + if (!iTimer->IsActive()) + { + iTimer->Start(iTimerInterval, iTimerInterval, + TCallBack(TimerCallback, this)); + } + } + } + } + } + +/** + * Notify listener + */ +void CPosModulesStatus::NotifyListeners(TPositionModuleStatusEvent& aOccurredEvent) + { + TInt count = iListenerArray.Count(); + for ( TInt i = 0; i < count; i++ ) + { + iListenerArray[i]->HandleModuleStatusChanged( + aOccurredEvent ); + } + } + +/** + * Notify event to subscriber + */ +void CPosModulesStatus::NotifyEventToSubscriber(TPositionModuleStatusEvent& aOccurredEvent, const CPosModulesStatus::TPosSubscriber& aSubscriber) + { + aOccurredEvent.SetRequestedEvents(aSubscriber.iEvent.RequestedEvents()); + + DEBUG_TRACE("Writing event object in", __LINE__); + // Write back to client + TPckgC eventPckg(aOccurredEvent); + TInt res = Global::Write(aSubscriber.iMsg, KParamModuleStatusEvent, eventPckg); + if (res == KErrNone) + { + RequestComplete(aSubscriber.iMsg, KErrNone); + } + DEBUG_TRACE("Writing event object out", __LINE__); + } + +/** + * Timer callback + */ +TInt CPosModulesStatus::TimerCallback(TAny* aModulesStatus) + { + CPosModulesStatus* moduleStatus = + reinterpret_cast (aModulesStatus); + return moduleStatus->DoTimerCallback(); + } + +/** + * timer callback handler function + */ +TInt CPosModulesStatus::DoTimerCallback() + { + TBool timerIsNeeded = EFalse; + for (TInt i = iSubscribers.Count() - 1; i >= 0; i--) + { + TPosSubscriber& subscriber = iSubscribers[i]; + if (!subscriber.iHasRequest) + { + if (subscriber.iToBeRemoved) + { + iSubscribers.Remove(i); + } + else + { + subscriber.iToBeRemoved = ETrue; + timerIsNeeded = ETrue; + } + } + } + + if (!timerIsNeeded) + { + iTimer->Cancel(); + return EFalse; + } + + return ETrue; + } + +/** + * Complete request + */ +void CPosModulesStatus::RequestComplete(const RMessage2& aMessage, TInt aCompleteCode) + { + if (!aMessage.IsNull()) + { + aMessage.Complete(aCompleteCode); + } + } + +// End of File