locationrequestmgmt/locationserver/src/EPos_CPosSubSession.cpp
author hgs
Tue, 13 Jul 2010 12:25:28 +0100
changeset 48 81c9bee26a45
parent 0 9cfd9a3ee49c
permissions -rw-r--r--
201025_02

// 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 <s32mem.h>
#ifdef SYMBIAN_FEATURE_MANAGER
	#include <featdiscovery.h>
	#include <featureuids.h>
#endif
#include <lbs.h>
#include <lbs/lbsadmin.h>
#include "lbslocservermessageenums.h"
#include <lbs/epos_cposmodules.h>
#include <lbs/epos_mposmodulesobserver.h>
#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<RRequestorStack*> (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;

#if defined __WINSCW__ && defined SYMBIAN_CELLMO_CENTRIC
	iLocationManagementSupported = EFalse;
#else
#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 // SYMBIAN_FEATURE_MANAGER
#endif // __WINSCW__ && defined SYMBIAN_CELLMO_CENTRIC
	
	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<CRequestor::TRequestorType> requestorType;
    User::LeaveIfError(Global::Read(aMessage, KParamRequestorType, requestorType));

    // the requestor must be a service
    if (requestorType() != CRequestor::ERequestorService)
        {
        User::Leave(KErrArgument);
        }

	TPckgBuf<CRequestor::TRequestorFormat> 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
        <TPositionUpdateOptionsBase&>(const_cast<TUint8&>(*optionsBuf->Ptr()));
    
    // Check update options. Leaves if not accepted values.

    Global::ValidatePositionClassBufferL(optionsBase, optionsBuf->Des());
    Global::ValidatePositionClassTypeL(optionsBase, EPositionUpdateOptionsClass);

    TPositionUpdateOptions& options = 
        static_cast<TPositionUpdateOptions&>(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
        <TPositionUpdateOptionsBase&>(const_cast<TUint8&>(*optionsBuf->Ptr()));
    
    Global::ValidatePositionClassBufferL(optionsBase, optionsBuf->Des());
    Global::ValidatePositionClassTypeL(optionsBase, EPositionUpdateOptionsClass);

    TPositionUpdateOptions& options = static_cast<TPositionUpdateOptions&>(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);
	}