datasourcemodules/defaultpositioningmodule/src/EPos_CPosRequestController.cpp
changeset 0 9cfd9a3ee49c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datasourcemodules/defaultpositioningmodule/src/EPos_CPosRequestController.cpp	Tue Feb 02 01:50:39 2010 +0200
@@ -0,0 +1,836 @@
+// Copyright (c) 2007-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 <ecom/ecom.h>
+
+#include <lbscommon.h>
+#include <lbspositioninfo.h>
+#include <lbs/epos_cposmodules.h>
+#include <lbs/epos_cposmoduleidlist.h>
+#include <lbs/epos_cpositioner.h>
+#include <lbssatellite.h>
+#include "epos_mposmodulestatusmanager.h"
+
+#include "EPos_CPosRequestController.h"
+#include "epos_cposrequestor.h"
+#include "epos_defaultproxycommon.h"
+#include "epos_cpospsylisthandler.h"
+#include "epos_cpospsyfixstatemanager.h"
+#include "epos_cposconstmanager.h"
+#include "epos_cposexternalgpsmonitor.h"
+#include "epos_posgenericinfouser.h"
+
+
+// ================= LOCAL FUNCTIONS =======================
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CPosRequestController::CPosRequestController(
+    CPosDefaultPositioner& aDefaultPositioner, 
+    MPosModuleStatusManager& aModuleStatusManager)
+    :
+    iDefaultPositioner( aDefaultPositioner ),
+    iModuleStatusManager( aModuleStatusManager ),
+    iCurrentPsy( KErrNotFound )
+    {
+    }
+
+// EPOC default constructor can leave.
+void CPosRequestController::ConstructL(
+        MPosModuleSettingsManager& aSettingsManager )
+    {
+    TRACESTRING( "CPosRequestController::ConstructL start... " )
+    
+    iPsyListHandler = CPosPsyListHandler::GetInstanceL();
+    iPsyListHandler->SetModuleSettingsManagerL( 
+        aSettingsManager );
+    iPsyListHandler->AddListenerL( this );
+
+    
+    iPsyFixStateManager = CPosPsyFixStateManager::GetInstanceL();
+    iPsyFixStateManager->AddListenerL( this );
+    iConstManager = CPosConstManager::GetInstanceL();
+
+    iExtGpsPsyMonitor = CPosExternalGpsMonitor::GetInstanceL( 
+        iDefaultPositioner,
+        iModuleStatusManager );
+
+    //Construct cleanup timer
+    iCleanupTimer = CPeriodic::NewL( CActive::EPriorityStandard );
+
+    TRACESTRING( "CPosRequestController::ConstructL end " )
+    
+    }
+
+// Two-phased constructor.
+CPosRequestController* CPosRequestController::NewL(
+    CPosDefaultPositioner& aDefaultPositioner,
+    MPosModuleSettingsManager& aSettingsManager,
+    MPosModuleStatusManager& aModuleStatusManager )
+    {
+    CPosRequestController* self = new (ELeave)
+        CPosRequestController(
+            aDefaultPositioner,
+            aModuleStatusManager );
+
+    CleanupStack::PushL(self);
+    self->ConstructL( 
+        aSettingsManager );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// Destructor
+CPosRequestController::~CPosRequestController()
+    {
+    TRACESTRING( "CPosRequestController::destructor start... " )
+    
+    if ( iPsyFixStateManager )
+        {
+        iPsyFixStateManager->RemoveListener( this );
+        iPsyFixStateManager->ReleaseInstance();
+        }
+    
+    if ( iPsyListHandler )
+        {
+        iPsyListHandler->RemoveListener( this );
+        iPsyListHandler->ReleaseInstance();
+        }
+        
+    if ( iConstManager )
+        {
+        iConstManager->ReleaseInstance();
+        }
+        
+    if ( iExtGpsPsyMonitor )
+        {
+        iExtGpsPsyMonitor->ReleaseInstance(
+            iDefaultPositioner );
+        }
+
+    // Close all requestors 
+    iRequestorArray.ResetAndDestroy();
+    iRequestorArray.Close();
+    
+    //Close PSY List
+    iPsyList.Close();
+    
+    // Cleanup timer
+    delete iCleanupTimer;
+
+    TRACESTRING( "CPosRequestController::destructor end... " )
+
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::NotifyPositionUpdate
+// ---------------------------------------------------------
+//
+void CPosRequestController::NotifyPositionUpdate(
+    TPositionInfoBase& aPosInfo,
+    TRequestStatus& aStatus)
+    {
+    TRACESTRING( "CPosRequestController::NotifyPositionUpdate start... " )
+
+    //Default Proxy can't handle simultaneous location request.
+    __ASSERT_DEBUG( 
+        iPosRequestStatus == NULL, 
+        DefaultProxyPanic( EDefaultProxyPanic_SimualtaneousLR ) );
+    
+    aStatus = KRequestPending;
+    iPosRequestStatus = &aStatus;
+    iPosInfo = &aPosInfo;
+    
+    //When location request received, clear cleanup timer
+    iCleanupTimer->Cancel();
+    
+    TRAPD( err, StartPositionUpdateL() );
+    if( err != KErrNone )
+        {
+        CompleteRequest(err);
+        }
+
+    TRACESTRING( "CPosRequestController::NotifyPositionUpdate end " )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CancelNotifyPositionUpdate
+// ---------------------------------------------------------
+//
+void CPosRequestController::CancelNotifyPositionUpdate(TInt aCancelReason)
+    {
+    TRACESTRING( "CPosRequestController::CancelNotifyPositionUpdate(TInt) start... " )
+
+    //Cancel location request with error to all loaded requestor
+    TInt loadedRequestorCount = iRequestorArray.Count();
+    for ( TInt i = 0; i < loadedRequestorCount; i++ )
+        {
+        CancelRequest( i, aCancelReason );
+        }
+        
+    CompleteRequest(KErrCancel);
+
+    TRACESTRING( "CPosRequestController::CancelNotifyPositionUpdate(TInt) end " )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CancelNotifyPositionUpdate
+// ---------------------------------------------------------
+//
+void CPosRequestController::CancelNotifyPositionUpdate()
+    {
+    TRACESTRING( "CPosRequestController::CancelNotifyPositionUpdate start... " )
+
+    // This is a real user cancel
+    CancelNotifyPositionUpdate(KErrCancel);
+    
+    TRACESTRING( "CPosRequestController::CancelNotifyPositionUpdate end " )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CancelRequest
+// ---------------------------------------------------------
+//
+void CPosRequestController::CancelRequest( TInt aIndex, TInt aCancelReason )
+    {
+    TInt count = iRequestorArray.Count();
+    if ( aIndex < count )
+        {
+        CPosRequestor* requestor = iRequestorArray[aIndex];
+        if ( requestor->IsActive() )
+            {
+            //Notify external GPS PSY monitor that this PSY is not used.
+            iExtGpsPsyMonitor->PsyNotUsed( requestor->ModuleId() );
+            requestor->CancelWithReason(aCancelReason);
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CancelRequest
+// ---------------------------------------------------------
+//
+void CPosRequestController::CancelRequest( TPositionModuleId aPsyId )
+    {
+    TInt count = iRequestorArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CPosRequestor* requestor = iRequestorArray[i];
+        if ( requestor->ModuleId() == aPsyId && 
+            requestor->IsActive() )
+            {
+            //Notify external GPS PSY monitor that this PSY is not used.
+            iExtGpsPsyMonitor->PsyNotUsed( requestor->ModuleId() );
+            requestor->Cancel();
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::StartTrackingL
+// ---------------------------------------------------------
+//
+void CPosRequestController::StartTracking(
+    const TTimeIntervalMicroSeconds& /*aInterval*/)
+    {
+    //This function does nothing. Tracking will be started
+    //to any specific PSY only if this PSY will be used by
+    //Default Proxy. 
+
+    TRACESTRING( "CPosRequestController::StartTracking" )
+
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::StopTracking
+// ---------------------------------------------------------
+//
+void CPosRequestController::StopTracking()
+    {
+    TRACESTRING( "CPosRequestController::StopTracking start..." )
+    
+    //Stop tracking to all loaded PSYs
+    TInt loadedRequestorCount = iRequestorArray.Count();
+    for ( TInt i = 0; i < loadedRequestorCount; i++ )
+        {
+        iRequestorArray[i]->StopTracking();
+        }
+
+    TRACESTRING( "CPosRequestController::StopTracking end" )
+
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::StartPositionUpdateL
+// ---------------------------------------------------------
+//
+void CPosRequestController::StartPositionUpdateL()
+    {
+    TRACESTRING( "CPosRequestController::StartPositionUpdateL start..." )
+
+    //Rebuid PSY list if neccessary
+    if ( !iPsyListValid )
+        {
+        iPsyListHandler->GetPsyListL( iPsyList );
+        iPsyListValid = ETrue;
+        }
+        
+    iFirstResult = KErrNotFound;    // as if no enabled psys found
+    iCurrentPsy = KErrNotFound;     // start from first module
+    TryNextPositioner();
+    
+    if ( !IsLocationRequestOnGoing() )
+        {
+        CompleteRequest( iFirstResult );
+        }
+
+    TRACESTRING( "CPosRequestController::StartPositionUpdateL end" )
+
+    }
+
+
+// ---------------------------------------------------------
+// CPosRequestController::TryNextPositioner
+// ---------------------------------------------------------
+//
+void CPosRequestController::TryNextPositioner()
+{
+    TRACESTRING( "CPosRequestController::TryNextPositioner start..." )
+
+    // Find next enabled plugin we should try with
+    TInt count = iPsyList.Count();
+    while ( ++iCurrentPsy < count )
+        {
+        TPositionModuleId currentPsyId = iPsyList[iCurrentPsy];
+        
+        TRACESTRING2( "PSY: %x", currentPsyId )
+
+        TUint32 classType = iPosInfo->PositionClassType();
+        if ( !iPsyListHandler->IsClassSupported( 
+            classType,
+            currentPsyId ) )
+            {
+            //if the requested class is not supported, then we try next PSY
+            //in the PSY list
+            
+            if ( iCurrentPsy == 0 )
+                {
+                //Error code fromt the first PSY
+                iFirstResult = KErrArgument;
+                }
+
+            continue;
+            }
+            
+        TRAPD( err, TryPositionerL( currentPsyId ) );
+        
+        TRACESTRING2( "Try PSY completion code = %d", err )
+
+        if( err == KErrNone )
+            {
+            //Location request is made to currentPsy. Check the fix state of
+            //current PSY, if current PSY can't give a fix, we load next PSY
+            if ( iPsyFixStateManager->GetPsyFixState( currentPsyId ) 
+                != CPosPsyFixStateManager::EPsyFixStateNo )
+                {
+                //break from here. Othsewise, try next PSY
+                break;
+                }
+            }
+        else
+            {
+            //In error case, we store the error code if needed and try next PSY
+            if ( iCurrentPsy == 0 )
+                {
+                //Error code fromt the first PSY
+                iFirstResult = err;
+                }
+            }
+        }
+
+    TRACESTRING( "CPosRequestController::TryNextPositioner end" )
+
+}
+
+// ---------------------------------------------------------
+// CPosRequestController::TryPositionerL
+// ---------------------------------------------------------
+//
+void CPosRequestController::TryPositionerL( TPositionModuleId aPsyId )
+    {
+    CPosRequestor* currentRequestor = NULL;
+    
+    
+    //Check device status of the PSY. If it's in error status,
+    //it will not be used at all.
+    TPositionModuleStatus moduleStatus;
+    iModuleStatusManager.GetModuleStatus( 
+        aPsyId,
+        moduleStatus );
+    if ( moduleStatus.DeviceStatus() == TPositionModuleStatus::EDeviceError )
+        {
+        TRACESTRING2( "PSY %x device error", aPsyId )
+
+        User::Leave( KErrGeneral );
+        }
+    
+    //Find if the PSY is already loaded
+    TInt requestorCount = iRequestorArray.Count();
+    for ( TInt i = 0; i < requestorCount; i++ )
+        {
+        if ( iRequestorArray[i]->ModuleId() == aPsyId )
+            {
+            currentRequestor = iRequestorArray[i];
+            break;
+            }
+        }
+    
+    if ( currentRequestor == NULL )
+        {
+        //PSY has not been loaded before, load it now
+        TRACESTRING2( "Loading Positioner: %x", aPsyId )
+        currentRequestor = 
+            CPosRequestor::NewL(
+                iDefaultPositioner,
+                aPsyId,
+                *this,
+                *iPsyFixStateManager,
+                iModuleStatusManager );
+                
+        CleanupStack::PushL( currentRequestor );
+        
+        //Notify fix state manager that a PSY is loaded
+        iPsyFixStateManager->PsyLoadedL( aPsyId );
+        
+        //Add this requestor to requestor array
+        User::LeaveIfError( iRequestorArray.Append( 
+            currentRequestor ) );
+        CleanupStack::Pop( currentRequestor );
+        }
+        
+    //Start tracking if needed
+    TTimeIntervalMicroSeconds interval = iDefaultPositioner.TrackingInterval();
+    if (interval.Int64() != 0 )
+        {
+        currentRequestor->StartTrackingL( interval );
+        }
+    
+    //Make location request to current positioner
+    currentRequestor->MakeLocationRequestL( *iPosInfo );
+    
+    //Notify external GPS PSY monitor that a PSY is used
+    iExtGpsPsyMonitor->PsyUsed( aPsyId );
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::LocationRequestCompleted
+// ---------------------------------------------------------
+//
+void CPosRequestController::LocationRequestCompleted( 
+            TPositionModuleId aModuleId,
+            TInt aErr,
+            const TPositionInfoBase& aPosInfo,
+            TBool aIsPosInfoUpToDate )
+    {
+    TRACESTRING( "CPosRequestController::LocationRequestCompleted start..." )
+    TRACESTRING2( "PSY: %x", aModuleId )
+    TRACESTRING2( "Err: %d", aErr )
+    TRACESTRING2( "Is PosInfo Updated: %d", aIsPosInfoUpToDate )
+
+    //Notify the external GPS PSY monitor that a PSY in not used
+    iExtGpsPsyMonitor->PsyNotUsed( aModuleId );
+
+    TInt err = aErr;
+    if ( aErr == KPositionPartialUpdate && IsLocationRequestOnGoingOnNetworkPsy() )
+        {
+        //Partial update is returned when Network PSY is used.
+        //partial update is not forwarded to system. Instead, location
+        //request is made to the loaded PSY again.
+        TInt ignore;
+        TRAP( ignore, TryPositionerL( aModuleId ) );
+        }
+    else if ( aErr == KErrNone || 
+        aErr == KErrPositionBufferOverflow ||
+        aErr == KPositionPartialUpdate  )
+        {
+        //Location request succeed or
+        //buffer over flow is returned from a PSY or
+        //partial update is returned when only GPS PSY is used
+        
+        //Copy request info, and complete LR
+        if ( aIsPosInfoUpToDate )
+            {
+            __ASSERT_DEBUG( 
+                aPosInfo.PositionClassSize() == iPosInfo->PositionClassSize(),
+                DefaultProxyPanic( EDefaultProxyPanic_PosInfoSizeMismatch ) );
+            
+            Mem::Copy( iPosInfo, &aPosInfo, iPosInfo->PositionClassSize() );
+            }
+        else
+            {
+            TInt cpErr = CopyPosInfoClass( aPosInfo , *iPosInfo );
+            if ( cpErr != KErrNone && err == KErrNone )
+                {
+                err = cpErr;
+                }
+            }
+        
+        if ( iPosInfo->ModuleId() != aModuleId )
+            {
+            err = KErrGeneral;
+            }
+            
+        CompleteRequest( err );
+        }
+    else
+        {
+        if ( aModuleId == iPsyList[0] )
+            {
+            //Store the result from first PSY
+            iFirstResult = aErr;
+            
+            //Store module ID of first positioner
+            iPosInfo->SetModuleId( aModuleId );
+            }
+        }
+        
+    //This will cause the state change notification and generate fallback 
+    //if it's a error case.
+    iPsyFixStateManager->SetPsyFixState( aModuleId, aErr );
+    
+    if ( !IsLocationRequestOnGoing() )
+        {
+        CompleteRequest( iFirstResult );
+        }
+
+    TRACESTRING( "CPosRequestController::LocationRequestCompleted end" )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::IsLocationRequestOnGoing
+// ---------------------------------------------------------
+//
+TBool CPosRequestController::IsLocationRequestOnGoing() const
+    {
+    TInt count = iRequestorArray.Count();
+    for ( TInt i=0; i < count; i++ )
+        {
+        const CPosRequestor& requestor = *(iRequestorArray[i]);
+        if ( requestor.IsActive() )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::IsLocationRequestOnGoingOnNetworkPsy
+// ---------------------------------------------------------
+//
+TBool CPosRequestController::IsLocationRequestOnGoingOnNetworkPsy() const
+    {
+    TInt count = iRequestorArray.Count();
+    for ( TInt i=0; i < count; i++ )
+        {
+        const CPosRequestor& requestor = *(iRequestorArray[i]);
+        if ( requestor.IsActive() && 
+            iPsyListHandler->IsModuleNetworkBased(
+                requestor.ModuleId() ) )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::PsyFixStateChanged
+// ---------------------------------------------------------
+//
+void CPosRequestController::PsyFixStateChanged( 
+            TPositionModuleId aModuleId,
+            CPosPsyFixStateManager::TPsyFixState aFixState )
+    {
+    TRACESTRING( "CPosRequestController::PsyFixStateChanged start..." )
+    TRACESTRING2( "PSY: %x", aModuleId )
+    TRACESTRING2( "Fix state: %d", aFixState )
+
+    //If there is location request on going and
+    //current can't give a fix, we try next PSY
+    if( iPosRequestStatus && iCurrentPsy<iPsyList.Count() )
+        {
+        if ( aFixState == CPosPsyFixStateManager::EPsyFixStateNo &&
+            iPsyList[iCurrentPsy] == aModuleId )
+            {
+            TryNextPositioner();
+            }
+        }
+
+    TRACESTRING( "CPosRequestController::PsyFixStateChanged end" )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CompleteRequest
+// ---------------------------------------------------------
+//
+void CPosRequestController::CompleteRequest(TInt aCompleteCode)
+    {
+    TRACESTRING( "CPosRequestController::CompleteRequest start..." )
+    TRACESTRING2( "Completion code: %d", aCompleteCode )
+    TRACESTRING2( "Module Id: %x", iPosInfo->ModuleId() )
+
+    if (iPosRequestStatus)
+        {
+        User::RequestComplete(iPosRequestStatus, aCompleteCode);
+        iPosRequestStatus = NULL;
+        
+        //Clear all location request if this is not 
+        //a partial update
+        if ( aCompleteCode != KPositionPartialUpdate )
+            {
+            ClearLocationRequests();
+            }
+            
+        //If there is still location request ongoing to other PSYs,
+        //start cleanup timer
+        TInt count = iRequestorArray.Count();
+        for ( TInt i = 0; i < count; i++ )
+            {
+            if ( iRequestorArray[i]->IsActive() )
+                {
+                
+                if ( !iCleanupTimer->IsActive() )
+                    {
+                    iCleanupTimer->Start(
+                        iConstManager->GetCleanupTimeoutValue().Int64(),
+                        iConstManager->GetCleanupTimeoutValue().Int64(),
+                        TCallBack( CleanupTimeoutCallback, this )
+                        );
+                    }
+                }
+            }
+        }
+    TRACESTRING( "CPosRequestController::CompleteRequest end" )
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::ClearLocationRequests
+// ---------------------------------------------------------
+//
+void CPosRequestController::ClearLocationRequests()
+    {
+    TInt count = iRequestorArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CancelRequest( i, KErrCancel);
+        }
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::PsyListChanged
+// ---------------------------------------------------------
+//
+void CPosRequestController::PsyListChanged( 
+            const TPosPsyListChangeEvent& aEvent )
+    {
+    TRACESTRING( "CPosRequestController::PsyListChanged start..." )
+    TRACESTRING2( "Event type: %d", aEvent.iType )
+    TRACESTRING2( "PSY: %x", aEvent.iPsyId )
+    
+    switch ( aEvent.iType )
+        {
+        case EPosPsyListChangeEventPsyDeleted:
+            {
+            //Cancel location request to this PSY
+            CancelRequest( aEvent.iPsyId );
+                    
+            if ( iCurrentPsy >= 0 && iCurrentPsy < iPsyList.Count() )
+                {
+                //If there is location request on going
+                if ( aEvent.iPsyId == iPsyList[iCurrentPsy] )
+                    {
+                    //fallback to next PSY
+                    TryNextPositioner();
+                    }
+                }
+            //Delete this PSY from the list
+            TInt index = iPsyList.Find( aEvent.iPsyId );
+            if ( index != KErrNotFound )
+                {
+                iPsyList.Remove( index );
+                }
+                
+            //Unload this PSY
+            UnloadRequestor( aEvent.iPsyId );
+            }
+            break;
+        case EPosPsyListChangeEventListRebuild:
+        default:
+            //Rebuild the list
+            iPsyListValid = EFalse;
+            break;
+        }
+
+    TRACESTRING( "CPosRequestController::PsyListChanged end" )
+    }
+
+
+// ---------------------------------------------------------
+// CPosRequestController::GetRequestor
+// ---------------------------------------------------------
+//
+CPosRequestor* CPosRequestController::GetRequestor(
+            TPositionModuleId aPsyId )
+    {
+    TInt count = iRequestorArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        if ( iRequestorArray[i]->ModuleId() == aPsyId )
+            {
+            return iRequestorArray[i];
+            }
+        }
+    return NULL;
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::UnloadRequestor
+// ---------------------------------------------------------
+//
+void CPosRequestController::UnloadRequestor( TPositionModuleId aPsyId )
+    {
+    TRACESTRING( "CPosRequestController::UnloadRequestor" )
+    TRACESTRING2( "PSY: %x", aPsyId )
+
+    TInt count = iRequestorArray.Count();
+    for ( TInt i = count-1; i >= 0; i-- )
+        {
+        if ( iRequestorArray[i]->ModuleId() == aPsyId )
+            {
+            delete iRequestorArray[i];
+            iRequestorArray.Remove( i );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CopyPosInfoClass
+// ---------------------------------------------------------
+//
+TInt CPosRequestController::CopyPosInfoClass(
+            const TPositionInfoBase& aSrc,
+            TPositionInfoBase& aDst )
+    {
+    TInt err = KErrNone;
+    
+    TUint32 srcClasses = aSrc.PositionClassType();
+    TUint32 dstClasses = aDst.PositionClassType();
+    
+    //Handle TPositionInfoBase
+    aDst.SetModuleId( aSrc.ModuleId() );
+    aDst.SetUpdateType( aSrc.UpdateType() );
+    
+    //Handle TPositionInfo
+    if ( ( srcClasses & EPositionInfoClass ) &&
+        ( dstClasses & EPositionInfoClass ) )
+        {
+        TPosition pos;
+        static_cast < const TPositionInfo& > ( aSrc ).GetPosition( pos );
+        static_cast < TPositionInfo& > ( aDst ).SetPosition( pos );
+        }
+        
+    //Handle TPositionCourseInfo
+    if ( ( srcClasses & EPositionCourseInfoClass ) &&
+        ( dstClasses & EPositionCourseInfoClass ) )
+        {
+        TCourse course;
+        static_cast < const TPositionCourseInfo& > ( aSrc ).GetCourse( course );
+        static_cast < TPositionCourseInfo& > ( aDst ).SetCourse( course );
+        }
+        
+    //Handle TPositionSatelliteInfo
+    if ( ( srcClasses & EPositionSatelliteInfoClass ) &&
+        ( dstClasses & EPositionSatelliteInfoClass ) )
+        {
+        const TPositionSatelliteInfo& srcSat = 
+            static_cast < const TPositionSatelliteInfo& > ( aSrc );
+        TPositionSatelliteInfo& dstSat = 
+            static_cast < TPositionSatelliteInfo& > ( aDst );
+
+        dstSat.SetSatelliteTime( srcSat.SatelliteTime() );
+        dstSat.SetHorizontalDoP( srcSat.HorizontalDoP() );
+        dstSat.SetTimeDoP( srcSat.TimeDoP() );
+        dstSat.SetVerticalDoP( srcSat.VerticalDoP() );
+        
+        dstSat.ClearSatellitesInView();
+        TInt numSatData = srcSat.NumSatellitesInView();
+        
+        for ( TInt i = 0; i < numSatData; i++ )
+            {
+            TSatelliteData satData;
+            srcSat.GetSatelliteData( i, satData );
+            err = dstSat.AppendSatelliteData( satData );
+            if ( err != KErrNone )
+                {
+                return KErrNone;
+                }
+            }
+        }
+        
+    //Handle HPositionGenericInfo
+    if ( ( srcClasses & EPositionGenericInfoClass ) &&
+        ( dstClasses & EPositionGenericInfoClass ) )
+        {
+        const HPositionGenericInfo& srcGen = 
+            static_cast < const HPositionGenericInfo& > ( aSrc );
+        HPositionGenericInfo& dstGen = 
+            static_cast < HPositionGenericInfo& > ( aDst );
+        
+        err = PosGenericInfoUser::CopyHGenericInfo( srcGen, dstGen );
+        }
+    
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CPosRequestController::CleanupTimeoutCallback
+// ---------------------------------------------------------
+//
+TInt CPosRequestController::CleanupTimeoutCallback( TAny* aAny )
+    {
+    reinterpret_cast< CPosRequestController* > ( aAny ) ->
+        CleanupTimeout();
+    return KErrNone;
+    }
+        
+// ---------------------------------------------------------
+// CPosRequestController::CleanupTimeout
+// ---------------------------------------------------------
+//
+void CPosRequestController::CleanupTimeout()
+    {
+    //Cleanup all outstanding location requests
+    ClearLocationRequests();
+    iCleanupTimer->Cancel();
+    }
+
+// End of file