locationmanager/locationtrail/src/clocationrecord.cpp
changeset 0 c53acadfccc6
child 1 acef663c1218
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/locationmanager/locationtrail/src/clocationrecord.cpp	Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,1120 @@
+/*
+* Copyright (c) 2006-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:  A class for recording and storing locations.
+*
+*/
+
+#include <e32cmn.h> 
+#include <LbsErrors.h>
+#include <LbsSatellite.h>
+
+#include "rlocationtrail.h"
+#include "clocationrecord.h"
+#include "cnetworkinfo.h"
+#include "locationmanagerdebug.h"
+#include "locationtraildefs.h"
+#include "locationtrailpskeys.h"
+#include "mdeconstants.h"
+#include <centralrepository.h>
+
+
+using namespace MdeConstants;
+
+// --------------------------------------------------------------------------
+// CLocationRecord::NewL
+// --------------------------------------------------------------------------
+//
+EXPORT_C CLocationRecord* CLocationRecord::NewL()
+    {
+    CLocationRecord* self = new (ELeave) CLocationRecord();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+        
+// --------------------------------------------------------------------------
+// CLocationRecord::CLocationRecord
+// --------------------------------------------------------------------------
+//  
+CLocationRecord::CLocationRecord()
+    : iNetworkInfoTimer( NULL ),
+    iState( RLocationTrail::ETrailStopped ),
+    iTrailCaptureSetting( RLocationTrail::ECaptureAll ),
+    iLocationCounter( 0 ),
+    iRequestCurrentLoc( EFalse ),
+    iTrailStarted( EFalse ),
+    iLastGPSFixState( EFalse ),
+    iLastLocationId( 0 )
+    {
+    iMaxTrailSize = KMaxTrailLength / KUpdateInterval;
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::ConstructL
+// --------------------------------------------------------------------------
+//    
+void CLocationRecord::ConstructL()
+    {
+    const TInt KMillion = 1000000;
+    TInt err = iProperty.Define( KPSUidLocationTrail, KLocationTrailState, RProperty::EInt );
+    if ( err != KErrNone && err != KErrAlreadyExists )
+        {
+        User::Leave( err );
+        }
+    User::LeaveIfError( iProperty.Set( KPSUidLocationTrail,
+        KLocationTrailState, (TInt) RLocationTrail::ETrailStopped ) ); 
+
+    iNetworkInfo = CNetworkInfo::NewL( this );
+    iPositionInfo = CPositionInfo::NewL( this );
+	iRemapper = CLocationRemappingAO::NewL();
+    iNetworkInfoTimer = CPeriodic::NewL( CActive::EPriorityStandard );
+    
+    TInt interval( 0 );
+    TRAP(err, ReadCenRepValueL(KIntervalKey, interval));
+    LOG1("CLocationManagerServer::ConstructL, cenrep interval value:%d", interval);
+    
+    if (interval == 0)
+    	{
+        LOG1("CLocationManagerServer::ConstructL, cenrep interval err:%d", err);
+    	iInterval = KUpdateInterval;
+    	}
+    else 
+    	{
+    	iInterval = interval * KMillion;
+    	}
+    
+    TInt trailLength( 0 );
+    TRAP(err, ReadCenRepValueL(KTrailLengthKey, trailLength));
+    LOG1("CLocationManagerServer::ConstructL, cenrep trail length value:%d", trailLength);
+    
+    if ( err != KErrNone )
+    	{
+        LOG1("CLocationManagerServer::ConstructL, cenrep trail length err:%d", err);
+    	iBufferSize = KMaxTrailLength / iInterval;
+    	}
+    else
+    	{
+    	iBufferSize = trailLength * KMillion / iInterval;
+    	}
+
+    TRAP(err, ReadCenRepValueL(KLocationDeltaKey, iLocationDelta));
+    LOG1("CLocationManagerServer::ConstructL, location delta value:%d", iLocationDelta);
+    
+    if (iLocationDelta == 0)
+    	{
+        LOG1("CLocationManagerServer::ConstructL, location delta err:%d", err);
+        iLocationDelta = KLocationDelta;
+    	}
+
+    }
+    
+// --------------------------------------------------------------------------
+// CLocationRecord::~CLocationRecord
+// --------------------------------------------------------------------------
+//    
+CLocationRecord::~CLocationRecord()
+    {
+    Stop();
+    iProperty.Delete( KPSUidLocationTrail, KLocationTrailState );
+    iProperty.Close();
+    iTrail.Close();
+    
+    delete iNetworkInfo;
+    delete iPositionInfo;
+    delete iNetworkInfoTimer;
+	if (iRemapper)
+		{
+		iRemapper->StopRemapping();
+		delete iRemapper;
+		}
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::CurrentState
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::LocationTrailState( TLocTrailState& aState )
+    {
+    aState = iState;
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::StartL
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::StartL( RLocationTrail::TTrailCaptureSetting aCaptureSetting )
+    {
+    LOG( "CLocationRecord::StartL(), begin" );
+    iTrailCaptureSetting = aCaptureSetting;
+    if ( aCaptureSetting == RLocationTrail::ECaptureAll && !iPositionInfo->IsActive() )
+        {
+        iPositionInfo->StartL( aCaptureSetting, iInterval );
+        }
+    else if ( aCaptureSetting == RLocationTrail::ECaptureNetworkInfo )
+    	{
+    	// Update and store network info in location trail immediately.
+    	// Timer will trigger the update again later.
+    	UpdateNetworkInfo( this );
+    	
+        if ( iNetworkInfoTimer && iNetworkInfoTimer->IsActive() )
+        	{
+        	iNetworkInfoTimer->Cancel();
+        	}
+        	
+        StartTimerL();
+    	}
+    
+    iLastLocationId = 0;
+    
+    SetCurrentState( RLocationTrail::ETrailStarting );
+    
+    iTrailStarted = ETrue;
+    LOG( "CLocationRecord::StartL(), end" );
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::Stop
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::Stop()
+    {
+    LOG( "CLocationRecord::StopL(), begin" );
+    iPositionInfo->Stop();
+    iTrailStarted = EFalse;
+    
+    if ( iNetworkInfoTimer && iNetworkInfoTimer->IsActive() )
+    	{
+    	iNetworkInfoTimer->Cancel();
+    	}
+
+    if ( iRemapper )
+    	{
+    	iRemapper->ResetQueue();
+    	}
+    SetCurrentState( RLocationTrail::ETrailStopped );
+    LOG( "CLocationRecord::StopL(), end" );
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::SetStateToStop
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::SetStateToStopping()
+	{
+	SetCurrentState( RLocationTrail::ETrailStopping );
+	}
+
+// --------------------------------------------------------------------------
+// CLocationRecord::GetLocationByTimeL
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::GetLocationByTimeL( const TTime aTime, 
+												   TLocationData& aLocationData,
+                                                   TLocTrailState& aState )
+    {
+    LOG( "CLocationRecord::GetLocationByTimeL(), begin" );
+    TInt posFound( EFalse );
+
+#ifdef _DEBUG
+    _LIT( KDateTimeFormat, "%Y/%M/%D %H:%T:%S" );
+    const TInt DateTimeStrMaxLength = 20;
+    LOG1( "CLocationRecord::GetLocationByTimeL - aTime: %Ld", aTime.Int64() );
+    TBuf<DateTimeStrMaxLength> str1;
+    aTime.FormatL( str1, KDateTimeFormat );
+    LOG1( "CLocationRecord::GetLocationByTimeL - aTime: %S", &str1 );
+#endif
+
+    TTimeIntervalSeconds interval;
+    TTimeIntervalSeconds nextInterval;
+    for ( TInt i(iTrail.Count()-1) ; i >= 0 && !posFound ; i-- )
+        {
+        TInt err = iTrail[i].iTimeStamp.SecondsFrom( aTime, interval );
+        
+        TInt timeDiff = Abs( interval.Int() );
+
+#ifdef _DEBUG
+        LOG1( "CLocationRecord::GetLocationByTimeL - Trail timestamp: %Ld", iTrail[i].iTimeStamp.Int64() );
+        TBuf<DateTimeStrMaxLength> str;
+        iTrail[i].iTimeStamp.FormatL( str, KDateTimeFormat );
+        LOG1( "CLocationRecord::GetLocationByTimeL - Trail timestamp: %S", &str );
+        LOG1( "CLocationRecord::GetLocationByTimeL - timeDiff: %d", timeDiff );
+#endif
+
+        if ( err == KErrNone && timeDiff <= KIntervalSeconds )
+            {
+            // The nearest time is in iTrail[i] or in iTrail[i-1].
+            if ( i > 0 )
+                {
+                iTrail[i-1].iTimeStamp.SecondsFrom( aTime, nextInterval );
+                
+                TInt nextDiff = Abs( nextInterval.Int() );
+                    
+                if ( nextDiff < timeDiff )
+                    {
+                    aLocationData = iTrail[i-1].iLocationData;
+                    aState = iTrail[i-1].iTrailState;
+                    }
+                else
+                    {
+                    aLocationData = iTrail[i].iLocationData;
+                    aState = iTrail[i].iTrailState;
+                    }                    
+                }            
+            else
+                {
+                aLocationData = iTrail[i].iLocationData;
+                aState = iTrail[i].iTrailState;
+                }
+            posFound = ETrue;
+            }
+        }
+    if ( !posFound )
+        {
+        User::Leave( KErrNotFound );
+        }
+    LOG( "CLocationRecord::GetLocationByTimeL(), end" );
+    }
+    
+// --------------------------------------------------------------------------
+// CLocationRecord::RequestLocationL
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::RequestLocationL()
+    {
+    iRequestCurrentLoc = ETrue;
+    if ( iTrailCaptureSetting != RLocationTrail::ECaptureNetworkInfo &&
+    	!iPositionInfo->IsActive() )
+        {
+        iPositionInfo->StartL( iTrailCaptureSetting, iInterval );
+        }
+    else if ( iTrailCaptureSetting == RLocationTrail::ECaptureNetworkInfo )
+    	{
+    	TPositionSatelliteInfo posInfo;
+    	CTelephony::TNetworkInfoV1 network = CTelephony::TNetworkInfoV1();
+    	GetNetworkInfo( network );
+       	iObserver->CurrentLocation( posInfo, network, KErrNone );
+        iRequestCurrentLoc = EFalse;
+    	}
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::CancelLocationRequest
+// --------------------------------------------------------------------------
+//    
+EXPORT_C void CLocationRecord::CancelLocationRequest()
+    {
+    iRequestCurrentLoc = EFalse;
+    if ( !iTrailStarted )
+        {
+        iPositionInfo->Stop();
+        }
+    }
+        
+        
+// --------------------------------------------------------------------------
+// CLocationRecord::GetNetworkInfo
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::GetNetworkInfo( CTelephony::TNetworkInfoV1& aNetworkInfo )
+    {
+    LOG("CLocationRecord::GetNetworkInfo");
+
+    aNetworkInfo = iNetwork;
+    }
+    
+// --------------------------------------------------------------------------
+// CLocationRecord::SetObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::SetObserver( MLocationTrailObserver* aObserver)
+    {
+    iObserver = aObserver;
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::SetAddObserver
+// --------------------------------------------------------------------------
+//
+EXPORT_C void CLocationRecord::SetAddObserver( MLocationAddObserver* aObserver)
+    {
+    iAddObserver = aObserver;
+    }
+
+// --------------------------------------------------------------------------
+// From MNetworkInfoObserver.
+// CLocationRecord::Position
+// --------------------------------------------------------------------------
+//    
+void CLocationRecord::Position( const TPositionInfo& aPositionInfo,
+                                const TInt aError  )
+    {    
+    const TPositionSatelliteInfo& positionSatelliteInfo = 
+    	static_cast<const TPositionSatelliteInfo&>(aPositionInfo);
+
+    if ( iRequestCurrentLoc )
+        {
+        HandleLocationRequest( positionSatelliteInfo, aError );
+        }
+    if( iState == RLocationTrail::ETrailStopped )
+    	{
+    	LOG("CLocationRecord::Position - trail stopped");
+    	return;
+    	}
+    
+    if ( !iTrailStarted )
+        {
+        iPositionInfo->NextPosition();
+        return;
+        }
+    switch ( aError )
+        {
+        case KPositionPartialUpdate: // fall through
+        case KPositionQualityLoss: 
+            {
+            // Location is stored, even if it may not be valid.
+            StoreLocation( positionSatelliteInfo ); 
+            LOG("CLocationRecord::Position - partial update");
+            if ( iState != RLocationTrail::EWaitingGPSData && 
+            	 iState != RLocationTrail::ETrailStopping ) 
+                {
+                SetCurrentState( RLocationTrail::EWaitingGPSData );
+            	LOG("CLocationRecord::Position trail waiting for gps");
+                }
+            break;
+            }
+        case KErrNone:
+            {
+            StoreLocation( positionSatelliteInfo );
+            LOG("CLocationRecord::Position - good GPS coordinates");
+            if ( iState != RLocationTrail::ETrailStarted ) 
+                {
+                if ( iRemapper )
+                	{
+                	LOG("CLocationRecord::Position start remapping");
+                	iLastLocationId = 0;
+                	TBool createLocation = iRemapper->CheckQueue();
+                	if( createLocation )
+                		{
+                		TRAP_IGNORE(	
+                		TItemId locationId = DoCreateLocationL( iNewItem.iLocationData );
+                		iRemapper->UpdateRelationsL( locationId );
+                		)
+                		}
+               		iRemapper->StartRemappingObjects( iNewItem.iLocationData );
+                	}
+                if ( iState != RLocationTrail::ETrailStopping )
+                	{
+                    SetCurrentState( RLocationTrail::ETrailStarted );
+                	LOG("CLocationRecord::Position trail started");
+                	}
+                }
+            break;
+            }
+        default:
+            {
+            StoreLocation( positionSatelliteInfo );
+            LOG1("CLocationRecord::Position - searching GPS, aError %d", aError );
+            if ( iState != RLocationTrail::ESearchingGPS &&
+               	 iState != RLocationTrail::ETrailStopping ) 
+                {
+                SetCurrentState( RLocationTrail::ESearchingGPS );
+            	LOG("CLocationRecord::Position trail searching gps");
+                }
+            break;
+            }      
+        }
+    TBool fixState = CheckGPSFix( positionSatelliteInfo );
+    LOG1( "CLocationRecord::Position fixState %d", fixState );
+    LOG1( "CLocationRecord::Position iLastGPSFixState %d", iLastGPSFixState );
+    
+    if ( iObserver && iLastGPSFixState != fixState )
+    	{
+    	LOG("CLocationRecord::Position quality changed");
+    	iObserver->GPSSignalQualityChanged( positionSatelliteInfo );
+    	}
+    
+   	iLastGPSFixState = fixState;
+    
+    iPositionInfo->NextPosition();
+    }
+
+TBool CLocationRecord::CheckGPSFix( const TPositionSatelliteInfo& aSatelliteInfo )
+	{
+	TPosition position;
+	aSatelliteInfo.GetPosition( position );
+	LOG1( "CLocationRecord::CheckGPSFix latitude %f", position.Latitude() );
+	LOG1( "CLocationRecord::CheckGPSFix longitude %f", position.Longitude() );
+	TBool ret = ( Math::IsNaN(position.Latitude()) || Math::IsNaN(position.Longitude()) ) 
+		? EFalse : ETrue;
+   	return ret;
+	}
+    
+// --------------------------------------------------------------------------
+// From MPositionerObserver.
+// CLocationRecord::NetworkInfo
+// --------------------------------------------------------------------------
+//    
+void CLocationRecord::NetworkInfo( const CTelephony::TNetworkInfoV1 &aNetworkInfo, 
+		const TInt aError )
+    {
+    LOG("CLocationRecord::NetworkInfo");
+    if ( aError == KErrNone )
+        {
+        LOG("CLocationRecord::NetworkInfo - KErrNone");
+        iNetwork = aNetworkInfo;
+        if (iNetwork.iAccess == CTelephony::ENetworkAccessUtran)
+        	{
+        	iNetwork.iLocationAreaCode = 0;
+        	}
+        if ( iState == RLocationTrail::ETrailStarting && iTrailStarted )
+        	{
+        	SetCurrentState( RLocationTrail::ETrailStarted );
+        	}
+        }
+    else
+        {
+        LOG1("CLocationRecord::NetworkInfo - %d", aError );
+        iNetwork = CTelephony::TNetworkInfoV1();
+        iNetwork.iAreaKnown = EFalse;
+        iNetwork.iAccess = CTelephony::ENetworkAccessUnknown;
+        iNetwork.iCellId = 0;
+        iNetwork.iLocationAreaCode = 0;
+        iNetwork.iCountryCode.Zero();
+        iNetwork.iNetworkId.Zero();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CLocationRecord::StoreLocationL
+// --------------------------------------------------------------------------
+//    
+void CLocationRecord::StoreLocation( const TPositionSatelliteInfo& aSatelliteInfo )
+    {
+    aSatelliteInfo.GetPosition( iNewItem.iLocationData.iPosition );
+    aSatelliteInfo.GetCourse( iNewItem.iLocationData.iCourse );
+    iNewItem.iLocationData.iSatellites = aSatelliteInfo.NumSatellitesUsed();
+    iNewItem.iLocationData.iQuality = aSatelliteInfo.HorizontalDoP();
+    
+    // Network info
+    GetNetworkInfo( iNewItem.iLocationData.iNetworkInfo );
+    // Get Universal time
+    iNewItem.iTimeStamp.UniversalTime();
+    iNewItem.iTrailState = iState;
+    
+    TInt error = iTrail.Append( iNewItem );
+    
+    // If appending an item to the trail fails because of OOM, remove oldest trail items
+    // until the new item fits or there's only one item left in the trail.
+    while ( error == KErrNoMemory && iTrail.Count() > 1 )
+		{
+		LOG("CLocationRecord::StoreLocation - Out of memory! Shortening trail!");
+		iTrail.Remove( 0 );
+		error = iTrail.Append( iNewItem );
+		}
+    
+    if ( iTrail.Count() > iMaxTrailSize )
+        {
+        iTrail.Remove( 0 );
+        }
+    
+    if( iAddObserver )
+    	{
+    	iAddObserver->LocationAdded( iNewItem, aSatelliteInfo );
+    	}
+    }
+    
+// --------------------------------------------------------------------------
+// CLocationRecord::SetCurrentState
+// --------------------------------------------------------------------------
+//        
+void CLocationRecord::SetCurrentState( TLocTrailState aState )    
+    {
+    LOG1( "CLocationRecord::SetCurrentState(), begin, state:%d", aState );
+    iState = aState;
+    iProperty.Set( KPSUidLocationTrail, KLocationTrailState, (TInt) aState );
+    if ( iObserver )
+        {
+        iObserver->LocationTrailStateChange();
+        }
+    LOG( "CLocationRecord::SetCurrentState(), end" );
+    }
+    
+// --------------------------------------------------------------------------
+// CLocationRecord::HandleLocationRequest
+// --------------------------------------------------------------------------
+//
+void CLocationRecord::HandleLocationRequest( const TPositionSatelliteInfo& aSatelliteInfo, 
+                                             const TInt aError )    
+    {
+	CTelephony::TNetworkInfoV1 network = CTelephony::TNetworkInfoV1();
+    if ( aError == KErrNone )
+        {
+       	GetNetworkInfo( network );
+        iObserver->CurrentLocation( aSatelliteInfo, network, aError );
+        iRequestCurrentLoc = EFalse;
+        if ( !iTrailStarted )
+            {
+            iPositionInfo->Stop();
+            }
+        }
+    else
+        {
+        iLocationCounter++;
+        if ( iLocationCounter > KCurrentLocTimeoutCount )
+            {
+            iObserver->CurrentLocation( aSatelliteInfo, network, KErrTimedOut );
+            iRequestCurrentLoc = EFalse;
+            iLocationCounter = 0;
+            if ( !iTrailStarted )
+                {
+                iPositionInfo->Stop();
+                }
+            }       
+        }    
+    }
+
+TInt CLocationRecord::UpdateNetworkInfo( TAny* aAny )
+	{
+	TPositionSatelliteInfo nullPositionInfo;
+	CLocationRecord* self = STATIC_CAST( CLocationRecord*, aAny );
+	self->StoreLocation( nullPositionInfo );
+	return KErrNone;
+	}
+
+
+EXPORT_C void CLocationRecord::CreateLocationObjectL( const TLocationData& aLocationData,
+		const TUint& aObjectId )
+	{
+	TItemId locationId = DoCreateLocationL( aLocationData );
+	CreateRelationL( aObjectId, locationId );
+	}
+
+
+EXPORT_C void CLocationRecord::LocationSnapshotL( const TUint& aObjectId )
+	{
+	LOG("CLocationRecord::LocationSnapshotL");
+	
+	TBool previousMatch = EFalse;
+	CMdENamespaceDef& namespaceDef = iMdeSession->GetDefaultNamespaceDefL();
+
+	// get locationdata from trail with object time
+	TTime timestamp = GetMdeObjectTimeL( aObjectId );
+	TLocationData locationData;
+	TLocTrailState state;
+	GetLocationByTimeL( timestamp, locationData, state );
+	
+	iObjectId = aObjectId;
+	iLocationData = locationData;
+
+	// capture only network data
+	if ( iTrailCaptureSetting == RLocationTrail::ECaptureNetworkInfo )
+		{
+		CTelephony::TNetworkInfoV1* net = &locationData.iNetworkInfo;
+		
+		if ( net->iCellId == 0 && 
+				net->iLocationAreaCode == 0 &&
+				net->iCountryCode.Length() == 0 &&
+				net->iNetworkId.Length() == 0 )
+			{
+			// nothing to do
+			LOG("CLocationRecord::LocationSnapshotL - no network info available");
+			}
+		else if ( iLastLocationId != 0 )
+			{
+			CTelephony::TNetworkInfoV1* lastnet = &iLastLocation.iNetworkInfo;
+			
+			// compare to previous network info
+			TItemId locationId = iLastLocationId;
+			if ( lastnet->iCellId != net->iCellId ||
+					lastnet->iLocationAreaCode != net->iLocationAreaCode ||
+					lastnet->iCountryCode != net->iCountryCode ||
+					lastnet->iNetworkId != net->iNetworkId )
+				{
+				LOG("CLocationRecord::LocationSnapshotL - network info changed");
+				locationId = DoCreateLocationL( locationData );
+				}
+			CreateRelationL( aObjectId, locationId );
+			}
+		else 
+			{
+			// new location
+			TItemId locationId = DoCreateLocationL( locationData );
+			CreateRelationL( aObjectId, locationId );
+			}
+		return;
+		}
+	
+	// coordinates empty (will be remapped)
+	if ( Math::IsNaN( locationData.iPosition.Latitude() ) && 
+			Math::IsNaN( locationData.iPosition.Longitude() ))
+		{
+		TRemapItem remapItem;
+		remapItem.iObjectId = aObjectId;
+		remapItem.iTime = timestamp;
+		
+		CTelephony::TNetworkInfoV1* net = &locationData.iNetworkInfo;
+
+		// no network info (offline mode + no GPS fix)
+		if ( net->iCellId == 0 && 
+				net->iLocationAreaCode == 0 &&
+				net->iCountryCode.Length() == 0 &&
+				net->iNetworkId.Length() == 0 )
+			{
+			LOG("CLocationRecord::LocationSnapshotL - empty remap item created");
+			}
+		// check match for last created locationobject
+		else if ( iLastLocationId != 0 )
+			{
+			TItemId locationId;
+			CTelephony::TNetworkInfoV1* lastnet = &iLastLocation.iNetworkInfo;
+
+			// networkinfo changed from last location
+			if ( lastnet->iCellId != net->iCellId ||
+					lastnet->iLocationAreaCode != net->iLocationAreaCode ||
+					lastnet->iCountryCode != net->iCountryCode ||
+					lastnet->iNetworkId != net->iNetworkId )
+				{
+				LOG("CLocationRecord::LocationSnapshotL - remap with new network info");
+				locationId = DoCreateLocationL( locationData );
+				}		
+			else
+				{
+				LOG("CLocationRecord::LocationSnapshotL - remap with previous network info");
+				locationId = iLastLocationId;
+				}
+			TItemId relationId = CreateRelationL( aObjectId, locationId );
+			remapItem.iLocationId = locationId;
+			remapItem.iRelationId = relationId;
+			}
+		else
+			{
+			// new location with only network data
+			TItemId locationId = DoCreateLocationL( locationData );
+			TItemId relationId = CreateRelationL( aObjectId, locationId );
+			remapItem.iLocationId = locationId;
+			remapItem.iRelationId = relationId;
+			}
+		iRemapper->Append( remapItem );
+		return;
+		}
+		
+	// valid coordinates found
+	if ( iLastLocationId != 0 )
+		{
+		CTelephony::TNetworkInfoV1* net = &locationData.iNetworkInfo;
+		CTelephony::TNetworkInfoV1* lastnet = &iLastLocation.iNetworkInfo;
+		
+		// first check if networkinfo matches last created location
+		if ( lastnet->iCellId == net->iCellId &&
+				lastnet->iLocationAreaCode == net->iLocationAreaCode &&
+				lastnet->iCountryCode == net->iCountryCode &&
+				lastnet->iNetworkId == net->iNetworkId )
+			{
+			LOG("CLocationRecord::LocationSnapshotL - network info matches");
+			
+			// if both locations have valid coordinates, calculate distance between points
+			if ( !Math::IsNaN( iLastLocation.iPosition.Latitude() ) && 
+					!Math::IsNaN( iLastLocation.iPosition.Longitude() ) && 
+					!Math::IsNaN( locationData.iPosition.Latitude() ) && 
+					!Math::IsNaN( locationData.iPosition.Longitude() ))
+				{
+				TReal32 distance;
+				TInt err = locationData.iPosition.Distance(iLastLocation.iPosition, distance);
+				
+				if ( distance < iLocationDelta )
+					{
+					LOG("CLocationRecord::LocationSnapshotL - location close to the previous one");
+					previousMatch = ETrue;
+					CreateRelationL( aObjectId, iLastLocationId );
+					LOG("CLocationRecord::CreateLocationObjectL - last location matched");
+					}
+				}
+			}
+		}
+	
+	// last location did not match, find existing one from DB
+	if( !previousMatch )
+		{
+		LOG("CLocationRecord::LocationSnapshotL - query location");
+		const TReal64 KMeterInDegrees = 0.000009;
+		const TReal64 KPi = 3.14159265358979;
+		const TReal32 K180Degrees = 180.0;
+	
+		TReal64 latitude = locationData.iPosition.Latitude();
+		TReal64 longitude = locationData.iPosition.Longitude();
+		// calculate distance in degrees
+		TReal64 cosine;
+		Math::Cos(cosine, locationData.iPosition.Latitude() * KPi / K180Degrees );
+		TReal64 latDelta = iLocationDelta * KMeterInDegrees;
+		TReal64 lonDelta = latDelta * cosine;
+		
+		CMdEObjectDef& locationObjectDef = namespaceDef.GetObjectDefL( Location::KLocationObject );
+		
+		CMdEPropertyDef& latitudeDef = locationObjectDef.GetPropertyDefL(
+				Location::KLatitudeProperty );
+		CMdEPropertyDef& longitudeDef = locationObjectDef.GetPropertyDefL(
+				Location::KLongitudeProperty );
+		CMdEPropertyDef& cellIdDef = locationObjectDef.GetPropertyDefL(
+				Location::KCellIdProperty );
+		CMdEPropertyDef& locationCodeDef = locationObjectDef.GetPropertyDefL( 
+				Location::KLocationAreaCodeProperty );
+		CMdEPropertyDef& countryCodeDef = locationObjectDef.GetPropertyDefL( 
+				Location::KCountryCodeProperty );
+		CMdEPropertyDef& networkCodeDef = locationObjectDef.GetPropertyDefL( 
+				Location::KNetworkCodeProperty );
+		
+		iLocationQuery = iMdeSession->NewObjectQueryL( namespaceDef, locationObjectDef, this );
+		CMdELogicCondition& cond = iLocationQuery->Conditions();
+		cond.SetOperator( ELogicConditionOperatorAnd );
+		
+		LOG1( "CLocationRecord::LocationSnapshotL latitude: %f", latitude);
+		LOG1( "CLocationRecord::LocationSnapshotL latdelta: %f", latDelta);
+		LOG1( "CLocationRecord::LocationSnapshotL longitude: %f", longitude);
+		LOG1( "CLocationRecord::LocationSnapshotL londelta: %f", lonDelta);
+		
+		cond.AddPropertyConditionL( latitudeDef, 
+				TMdERealBetween( latitude - latDelta, latitude + latDelta ));
+		cond.AddPropertyConditionL( longitudeDef, 
+				TMdERealBetween( longitude - lonDelta, longitude + lonDelta ));
+		cond.AddPropertyConditionL( cellIdDef, 
+				TMdEUintEqual( locationData.iNetworkInfo.iCellId) );
+		cond.AddPropertyConditionL( locationCodeDef, 
+				TMdEUintEqual( locationData.iNetworkInfo.iLocationAreaCode) );
+		cond.AddPropertyConditionL( countryCodeDef, ETextPropertyConditionCompareEquals,
+				locationData.iNetworkInfo.iCountryCode );
+		cond.AddPropertyConditionL( networkCodeDef, ETextPropertyConditionCompareEquals,
+				locationData.iNetworkInfo.iNetworkId );
+		
+		iLocationQuery->FindL();			
+		}
+	}
+
+	
+TItemId CLocationRecord::DoCreateLocationL( const TLocationData& aLocationData )
+	{
+	LOG("CLocationRecord::DoCreateLocationL - start");
+	TItemId locationObjectId;
+	
+	CMdENamespaceDef& namespaceDef = iMdeSession->GetDefaultNamespaceDefL();
+
+	CMdEObjectDef& locationObjectDef = namespaceDef.GetObjectDefL( Location::KLocationObject );
+	
+	// required object properties
+	CMdEPropertyDef& creationDef = locationObjectDef.GetPropertyDefL(
+			Object::KCreationDateProperty );
+	CMdEPropertyDef& modifiedDef = locationObjectDef.GetPropertyDefL(
+			Object::KLastModifiedDateProperty );
+	CMdEPropertyDef& sizeDef = locationObjectDef.GetPropertyDefL(
+			Object::KSizeProperty );
+	CMdEPropertyDef& itemTypeDef = locationObjectDef.GetPropertyDefL(
+			Object::KItemTypeProperty );
+	CMdEPropertyDef& offSetDef = locationObjectDef.GetPropertyDefL( 
+			Object::KTimeOffsetProperty );
+
+	// location related properties
+	CMdEPropertyDef& cellIdDef = locationObjectDef.GetPropertyDefL(
+			Location::KCellIdProperty );
+	CMdEPropertyDef& latitudeDef = locationObjectDef.GetPropertyDefL(
+			Location::KLatitudeProperty );
+	CMdEPropertyDef& longitudeDef = locationObjectDef.GetPropertyDefL(
+			Location::KLongitudeProperty );
+	CMdEPropertyDef& altitudeDef = locationObjectDef.GetPropertyDefL(
+			Location::KAltitudeProperty );
+
+	CMdEPropertyDef& directionDef = locationObjectDef.GetPropertyDefL(
+			Location::KDirectionProperty );
+	CMdEPropertyDef& speedDef = locationObjectDef.GetPropertyDefL( 
+			Location::KSpeedProperty );
+	CMdEPropertyDef& locationCodeDef = locationObjectDef.GetPropertyDefL( 
+			Location::KLocationAreaCodeProperty );
+	CMdEPropertyDef& countryCodeDef = locationObjectDef.GetPropertyDefL( 
+			Location::KCountryCodeProperty );
+	CMdEPropertyDef& networkCodeDef = locationObjectDef.GetPropertyDefL( 
+			Location::KNetworkCodeProperty );
+	CMdEPropertyDef& qualityDef = locationObjectDef.GetPropertyDefL( 
+			Location::KQualityProperty );
+
+	// location object
+	CMdEObject* locationObject = NULL;
+
+	locationObject = iMdeSession->NewObjectL( locationObjectDef, Object::KAutomaticUri );
+	CleanupStack::PushL( locationObject );
+
+	TTime timestamp( 0 );
+	timestamp.UniversalTime();
+
+	TTimeIntervalSeconds timeOffset = User::UTCOffset();
+	TTime localTime = timestamp + timeOffset;
+	
+	// required object properties
+	locationObject->AddTimePropertyL( creationDef, localTime );
+	locationObject->AddTimePropertyL( modifiedDef, timestamp );
+	locationObject->AddUint32PropertyL( sizeDef, 0 ); // always zero size for location objects
+	locationObject->AddTextPropertyL( itemTypeDef, Location::KLocationItemType );
+	locationObject->AddInt16PropertyL( offSetDef, timeOffset.Int() / 60 );
+	
+	LOG1( "CLocationRecord::DoCreateLocationL - location created with stamp: %Ld", timestamp.Int64() );
+	
+	// location related properties
+	if ( !Math::IsNaN( aLocationData.iPosition.Latitude() ) && 
+		 !Math::IsNaN( aLocationData.iPosition.Longitude() ))
+		{
+		locationObject->AddReal64PropertyL( latitudeDef, aLocationData.iPosition.Latitude() );
+		locationObject->AddReal64PropertyL( longitudeDef, aLocationData.iPosition.Longitude() );
+		}
+	if ( !Math::IsNaN( aLocationData.iPosition.Altitude() ) )
+		{
+		locationObject->AddReal64PropertyL( altitudeDef, aLocationData.iPosition.Altitude() );
+		}
+	if ( !Math::IsNaN( aLocationData.iCourse.Course() ) )
+		{
+		locationObject->AddReal32PropertyL( directionDef, aLocationData.iCourse.Course() );
+		}
+	if ( !Math::IsNaN( aLocationData.iCourse.Speed() ) )
+		{
+		locationObject->AddReal32PropertyL( speedDef, aLocationData.iCourse.Speed() );
+		}
+	if ( !Math::IsNaN( aLocationData.iQuality ) )
+		{
+		locationObject->AddReal32PropertyL( qualityDef, aLocationData.iQuality );
+		}
+
+	// network related properties
+	if ( aLocationData.iNetworkInfo.iAreaKnown )
+		{
+		if ( aLocationData.iNetworkInfo.iAccess != CTelephony::ENetworkAccessUnknown )
+			{
+			locationObject->AddUint32PropertyL( cellIdDef, aLocationData.iNetworkInfo.iCellId );
+			
+			}
+		if ( aLocationData.iNetworkInfo.iLocationAreaCode != 0 &&
+			aLocationData.iNetworkInfo.iAccess != CTelephony::ENetworkAccessUnknown )
+			{
+			locationObject->AddUint32PropertyL( locationCodeDef, 
+					aLocationData.iNetworkInfo.iLocationAreaCode );
+			
+			}
+		if ( aLocationData.iNetworkInfo.iCountryCode.Length() > 0 )
+			{
+			locationObject->AddTextPropertyL( countryCodeDef, 
+					aLocationData.iNetworkInfo.iCountryCode );
+			
+			}
+		if ( aLocationData.iNetworkInfo.iNetworkId.Length() > 0 )
+			{
+			locationObject->AddTextPropertyL(networkCodeDef, aLocationData.iNetworkInfo.iNetworkId);
+			
+			}
+		}
+
+	// Add the location object to the database.
+	locationObjectId = iMdeSession->AddObjectL( *locationObject );
+
+	iLastLocationId = locationObjectId;
+	iLastLocation = aLocationData;
+
+	CleanupStack::PopAndDestroy( locationObject );
+	
+	LOG("CLocationRecord::DoCreateLocationL - end");
+	
+	return locationObjectId;
+	}
+
+
+TItemId CLocationRecord::CreateRelationL( const TUint& aObjectId, const TUint& aLocationId )
+	{ 
+	LOG("CLocationRecord::CreateRelationL - start");
+	CMdENamespaceDef& namespaceDef = iMdeSession->GetDefaultNamespaceDefL();
+	
+	// "contains" relation definition
+	CMdERelationDef& containsRelDef = namespaceDef.GetRelationDefL( 
+			Relations::KContainsLocation );
+
+	CMdERelation* relationObject = iMdeSession->NewRelationLC( containsRelDef,
+			aObjectId, aLocationId, 0 );
+	if ( !relationObject )
+		{
+		User::Leave( KErrBadHandle );
+		}
+	TItemId relationId = iMdeSession->AddRelationL( *relationObject );
+
+	CleanupStack::PopAndDestroy( relationObject );
+	LOG("CLocationRecord::CreateRelationL - end");
+	
+	return relationId; 
+	}
+
+// --------------------------------------------------------------------------
+// CLocationManagerServer::ReadCenRepValueL
+// --------------------------------------------------------------------------
+//
+void CLocationRecord::ReadCenRepValueL(TInt aKey, TInt& aValue)
+	{
+	LOG( "CLocationRecord::::ReadCenRepValueL(), begin" );
+	CRepository* repository;
+	repository = CRepository::NewLC( KRepositoryUid );
+	User::LeaveIfError(repository->Get( aKey, aValue));
+	CleanupStack::PopAndDestroy(repository);
+    LOG( "CLocationRecord::::ReadCenRepValueL(), end" );   
+	}
+
+void CLocationRecord::HandleQueryNewResults(CMdEQuery& /*aQuery*/, TInt /*aFirstNewItemIndex*/, 
+		TInt /*aNewItemCount*/)
+	{
+	}
+
+void CLocationRecord::HandleQueryCompleted(CMdEQuery& aQuery, TInt aError)
+    {
+    LOG("CLocationRecord::HandleQueryCompleted - start");
+    const TInt count = aQuery.Count();
+    LOG1("CLocationRecord::HandleQueryCompleted count: %d", count);
+
+    CMdENamespaceDef* namespaceDef = NULL;
+
+    TRAP_IGNORE( namespaceDef = &iMdeSession->GetDefaultNamespaceDefL() );
+    if ( namespaceDef )
+        {
+        CMdEObjectDef* locationObjectDef = NULL;
+
+        TRAP_IGNORE( locationObjectDef = &namespaceDef->GetObjectDefL( Location::KLocationObject ) );
+        if ( locationObjectDef )
+        	{
+        	CMdEPropertyDef* latitudeDef = NULL;
+        	CMdEPropertyDef* longitudeDef = NULL;
+        	CMdEPropertyDef* altitudeDef = NULL;
+        	
+            TRAP_IGNORE( 
+            		latitudeDef = &locationObjectDef->GetPropertyDefL(
+            				Location::KLatitudeProperty );
+            		longitudeDef = &locationObjectDef->GetPropertyDefL(	
+            				Location::KLongitudeProperty );
+            		altitudeDef = &locationObjectDef->GetPropertyDefL( 
+            				Location::KAltitudeProperty );
+            		);
+
+            if( latitudeDef && longitudeDef && altitudeDef )
+            	{
+	            TBool created = EFalse;
+	            for ( TInt i = 0; i < count; i++ )
+	                {
+	                LOG1("CLocationRecord::HandleQueryCompleted check item: %d", i);
+	                CMdEItem& item = aQuery.ResultItem(i);
+	                CMdEObject& locationObject = static_cast<CMdEObject&>(item);
+	
+	                CMdEProperty* latProp = NULL;
+	                CMdEProperty* lonProp = NULL; 
+	                CMdEProperty* altProp = NULL;
+	
+	                locationObject.Property( *latitudeDef, latProp, 0 );
+	                locationObject.Property( *longitudeDef, lonProp, 0 );
+	                locationObject.Property( *altitudeDef, altProp, 0 );
+	
+	                if ( latProp && lonProp )
+	                    {
+	                    TReal32 distance;
+	                    TCoordinate newCoords;
+	                    if ( altProp )
+	                        {
+	                        TRAP_IGNORE( newCoords = TCoordinate( latProp->Real64ValueL(), lonProp->Real64ValueL(), (TReal32)altProp->Real64ValueL() ) );
+	                        }
+	                    else
+	                        {
+	                        TRAP_IGNORE( newCoords = TCoordinate( latProp->Real64ValueL(), lonProp->Real64ValueL() ) );
+	                        }
+	                    
+	                    const TInt err = iLocationData.iPosition.Distance(newCoords, distance);
+	                    
+	                    if ( distance < iLocationDelta )
+	                        {
+	                        LOG("CLocationRecord::HandleQueryCompleted - match found in db");
+	                        TRAPD( err, CreateRelationL( iObjectId, locationObject.Id() ) );
+	                        if( err == KErrNone)
+	                            {
+	                            created = ETrue;
+	                            i = count;
+	                            }
+	                        else
+	                            {
+	                            aError = err;
+	                            }
+	                        }
+	                    }
+	                }
+
+	            if ( !created && aError == KErrNone )
+	                {
+	                LOG("CLocationRecord::HandleQueryCompleted - no match found in db, create new");
+	                TInt locationId( 0 );
+	                TRAPD( err, locationId = DoCreateLocationL( iLocationData ) );
+	                LOG1("CLocationRecord::HandleQueryCompleted - DoCreateLocationL err: %d", err);
+	                if( err == KErrNone )
+	                    {
+	                    TRAP( err, CreateRelationL( iObjectId, locationId ));
+	                    LOG1("CLocationRecord::HandleQueryCompleted - CreateRelationL err: %d", err);
+	                    }
+	                }
+            	}
+            }
+        }
+
+    LOG("CLocationRecord::HandleQueryCompleted - end");
+    }
+
+EXPORT_C void CLocationRecord::SetMdeSession( CMdESession* aSession )
+	{
+	iMdeSession = aSession;
+	TRAPD(err, iRemapper->InitialiseL( aSession ));
+	if( err != KErrNone )
+		{
+		delete iRemapper;
+		iRemapper = NULL;
+		}
+	}
+
+void CLocationRecord::StartTimerL()
+	{
+	LOG("CLocationRecord::StartTimerL");
+	
+	if( !iNetworkInfoTimer->IsActive() )
+	    {
+	    iNetworkInfoTimer->Start( iInterval, iInterval, TCallBack( UpdateNetworkInfo, this ) );
+	    }
+	}
+
+TTime CLocationRecord::GetMdeObjectTimeL( TItemId aObjectId ) 
+    {
+    CMdENamespaceDef& namespaceDef = iMdeSession->GetDefaultNamespaceDefL();
+
+    CMdEObjectDef& objectDef = namespaceDef.GetObjectDefL( Object::KBaseObject );
+    CMdEPropertyDef& timeDef = objectDef.GetPropertyDefL( Object::KLastModifiedDateProperty );
+
+    CMdEObject* object = NULL;
+    CMdEProperty* property = NULL;
+    
+    object = iMdeSession->GetObjectL( aObjectId );
+    object->Property( timeDef, property, 0 );
+    if ( !property )
+        {
+        User::Leave( KErrNotFound );
+        }
+    return property->TimeValueL();
+    }
+
+EXPORT_C TBool CLocationRecord::RemappingNeeded()
+	{
+	return iRemapper->ItemsInQueue();
+	}
+
+// End of file