transistorsoft / react-native-background-geolocation

Sophisticated, battery-conscious background-geolocation with motion-detection
http://shop.transistorsoft.com/pages/react-native-background-geolocation
MIT License
2.65k stars 426 forks source link

Tracking occasionaly starts only after a long distance #1895

Closed paultranvan closed 10 months ago

paultranvan commented 10 months ago

We noticed that sometimes, the plugin will fire motion events and record location points only after the device moved for a long distance, e.g. several km, way beyond the distance filter or the stationary geofence. This happens both on Android and iOS.

Your Environment

Expected Behavior

The plugin should start tracking immediately when motion is detected on Android, or after the geofence exit on iOS (~200m).

Actual Behavior

We noticed that in some occasions, the plugin will fire motion events and location points quite late after the actual device motion. This behavior has been seen on a variety of devices :

The worse recorded case was a motion event only recorded 6km after the actual start, on iPhone SE. This happened while the device successfully recorded all the locations earlier the same day. From what we experienced, this mostly happen when the trip starts with a car, but there is not enough cases to conclude anything. Note that for the 2 Android devices, we followed the suggestions here: https://dontkillmyapp.com/

Is it something you also experienced on your own devices? Or are we missing something in the config?

Steps to Reproduce

Hard to reproduce, as it sometimes happens during real-life trips. Most of the time, the tracking works as expected and starts accordingly to the actual device motion.

Context

Tracking user trips based on location data, thanks to this plugin.

Debug logs

Here are 2 log examples, first on Android OnePlus 7, second on iPhone SE. For Android, the plugin is in headless mode. It is waken up at 08:47, while the trip actually started in car at 08:30, ~3km from there. For iOS, the activity is detected ~6km after the car motion.

Android Logs ``` 12-10 12:32:54.211 DEBUG [HeadlessTask$2 onHeadlessJsTaskFinish] taskId: 221 12-11 08:47:40.327 INFO [LoggerFacade$a a] ╔═════════════════════════════════════════════ ║ TSLocationManager version: 3.4.5 (427) ╠═════════════════════════════════════════════ ╟─ OnePlus HD1907 @ 12 (react) { "activityRecognitionInterval": 10000, "allowIdenticalLocations": false, "authorization": {}, "autoSync": false, "autoSyncThreshold": 0, "backgroundPermissionRationale": { "title": "Allow {applicationName} to access this device's location even when closed or not in use?", "message": "Mémoriser vos déplacements nécessite de ≪ {backgroundPermissionOptionLabel} ≫", "positiveAction": "Change to \"{backgroundPermissionOptionLabel}\"", "negativeAction": "" }, "batchSync": false, "configUrl": "", "debug": false, "deferTime": 0, "desiredAccuracy": -1, "desiredOdometerAccuracy": 100, "disableAutoSyncOnCellular": false, "disableElasticity": false, "disableLocationAuthorizationAlert": false, "disableMotionActivityUpdates": false, "disableProviderChangeRecord": false, "disableStopDetection": false, "distanceFilter": 10, "elasticityMultiplier": 1, "enableHeadless": true, "enableTimestampMeta": false, "extras": {}, "fastestLocationUpdateInterval": -1, "foregroundService": true, "geofenceInitialTriggerEntry": true, "geofenceModeHighAccuracy": false, "geofenceProximityRadius": 1000, "geofenceTemplate": "", "headers": {}, "headlessJobService": "com.transistorsoft.rnbackgroundgeolocation.HeadlessTask", "heartbeatInterval": -1, "httpRootProperty": "location", "httpTimeout": 60000, "isMoving": false, "locationAuthorizationRequest": "Always", "locationTemplate": "", "locationTimeout": 60, "locationUpdateInterval": 1000, "locationsOrderDirection": "ASC", "logLevel": 4, "logMaxDays": 5, "maxBatchSize": -1, "maxDaysToPersist": 10, "maxRecordsToPersist": -1, "method": "POST", "minimumActivityRecognitionConfidence": 75, "motionTriggerDelay": 0, "notification": { "layout": "", "title": "Service de localisation actif", "text": "Votre déplacement sera enregistré dans votre Cozy", "color": "", "channelName": "TSLocationManager", "channelId": "", "smallIcon": "mipmap\/ic_stat_ic_notification", "largeIcon": "", "priority": -1, "sticky": false, "strings": {}, "actions": [] }, "params": {}, "persist": true, "persistMode": 2, "schedule": [], "scheduleUseAlarmManager": false, "speedJumpFilter": 300, "startOnBoot": true, "stationaryRadius": 30, "stopAfterElapsedMinutes": 0, "stopOnStationary": false, "stopOnTerminate": false, "stopTimeout": 10, "triggerActivities": "in_vehicle, on_bicycle, on_foot, running, walking", "url": "", "useSignificantChangesOnly": false, "enabled": true, "schedulerEnabled": false, "trackingMode": 1, "odometer": 452468.3125, "isFirstBoot": false, "didLaunchInBackground": false, "didDeviceReboot": false } 12-11 08:47:40.330 INFO [LoggerFacade$a a] ╔═════════════════════════════════════════════ ║ DEVICE SENSORS ╠═════════════════════════════════════════════ ╟─ ✅ ACCELEROMETER: {Sensor name="lsm6dsm Accelerometer Non-wakeup", vendor="STMicro", version=142606, type=1, maxRange=78.4532, resolution=0.0023928226, power=0.15, minDelay=5000} ╟─ ✅ GYROSCOPE: {Sensor name="lsm6dsm Gyroscope Non-wakeup", vendor="STMicro", version=142606, type=4, maxRange=34.905033, resolution=0.0012216945, power=0.555, minDelay=5000} ╟─ ✅ MAGNETOMETER: {Sensor name="mmc5603x Magnetometer Non-wakeup", vendor="memsic", version=10220072, type=2, maxRange=3000.0288, resolution=0.0976, power=1.0, minDelay=10000} ╟─ ✅ SIGNIFICANT_MOTION: {Sensor name="sns_smd Wakeup", vendor="qualcomm", version=1, type=17, maxRange=1.0, resolution=1.0, power=0.025, minDelay=-1} ╚═════════════════════════════════════════════ 12-11 08:47:40.331 DEBUG [LoggerFacade$a a] 🎾 START [GeofencingService startId: 1, eventCount: 1] 12-11 08:47:40.337 INFO [TSGeofenceManager start] 🎾 Start monitoring geofences 12-11 08:47:40.360 INFO [BackgroundGeolocation ] ✅ Google Play Services: connected (version code:12451000) 12-11 08:47:40.360 DEBUG [LifecycleManager onCreate] ☯️ onCreate 12-11 08:47:40.364 DEBUG [TSConfig e] ℹ️ Persist config, dirty: [isMoving] 12-11 08:47:40.366 DEBUG [TSLocationManager b] ℹ️ Load last odometer location: Location[TSLocationManager 48.77****,2.32**** hAcc=24.526 et=0 {Bundle[{odometer=452468.3}]}] 12-11 08:47:40.370 DEBUG [HttpService startMonitoringConnectivityChanges] 🎾 Start monitoring connectivity changes 12-11 08:47:40.377 INFO [HeartbeatService stop] 🔴 Stop heartbeat 12-11 08:47:40.402 INFO [TSProviderManager startMonitoring] 🎾 Start monitoring location-provider changes 12-11 08:47:40.403 DEBUG [HttpService a] ╔═════════════════════════════════════════════ ║ 📶 Connectivity change: connected? true ╠═════════════════════════════════════════════ 12-11 08:47:40.408 INFO [TrackingService changePace] 🔵 setPace: false → true 12-11 08:47:40.409 DEBUG [TSGeofenceManager$f run] ╔═════════════════════════════════════════════ ║ TSGeofenceManager monitoring 0/0 ╠═════════════════════════════════════════════ ╚═════════════════════════════════════════════ 12-11 08:47:40.410 INFO [GeofencingService b] ╔═════════════════════════════════════════════ ║ GeofencingService: Stationary geofence EXIT ╠═════════════════════════════════════════════ ╟─ 📍 Location[fused 48.77****,2.35**** hAcc=15.859 et=+32d15h20m43s84ms alt=135.0 vAcc=1.7547628 {Bundle[mParcelledData.dataSize=108]}] 12-11 08:47:40.411 DEBUG [AbstractService a] ⚙️︎ FINISH [GeofencingService startId: 1, eventCount: 0, sticky: false] 12-11 08:47:40.412 INFO [ActivityRecognitionService start] 🎾 Start motion-activity updates 12-11 08:47:40.417 INFO [TSLocationManager requestLocationUpdates] 🎾 Location-services: ON 12-11 08:47:40.417 DEBUG [TSConfig translateDesiredAccuracy] translateDesiredAccuracy (true): -1 12-11 08:47:40.425 DEBUG [SQLiteLocationDAO prune] ℹ️ PRUNE -10 days 12-11 08:47:40.447 DEBUG [AbstractService a] 🎾 START [TrackingService startId: 1, eventCount: 1] 12-11 08:47:40.452 INFO [TrackingService k] ╔═════════════════════════════════════════════ ║ TrackingService motionchange: true ╠═════════════════════════════════════════════ 12-11 08:47:40.453 DEBUG [AbstractService a] ⚙️︎ FINISH [TrackingService startId: 1, eventCount: 0, sticky: true] 12-11 08:47:40.470 DEBUG [HeadlessTask onHeadlessEvent] 💀 event: connectivitychange 12-11 08:47:40.498 DEBUG [LifecycleManager b] ╔═════════════════════════════════════════════ ║ ☯️ HeadlessMode? true ╠═════════════════════════════════════════════ 12-11 08:47:40.500 DEBUG [HeadlessTask onHeadlessEvent] 💀 event: geofenceschange 12-11 08:47:40.507 DEBUG [HeadlessTask onHeadlessEvent] 💀 event: providerchange 12-11 08:47:40.576 INFO [TSLocationManager a] ╔═════════════════════════════════════════════ ║ motionchange LocationResult: 1 (3979ms old) ╠═════════════════════════════════════════════ ╟─ 📍 Location[fused 48.77****,2.35**** hAcc=15.859 et=+32d15h20m43s84ms alt=135.0 vAcc=1.7547628 {Bundle[{battery_level=0.97, is_charging=false, odometer=452468.3}]}], time: 1702280856593 12-11 08:47:40.579 INFO [TSLocationManager onSingleLocationResult] 🔵 Acquired motionchange position, isMoving: true 12-11 08:47:40.580 DEBUG [TSLocationManager a] Median accuracy: 15.859 12-11 08:47:40.767 DEBUG [HeadlessTask onHeadlessEvent] 💀 event: location 12-11 08:47:40.780 DEBUG [HeadlessTask$2 onHeadlessJsTaskStart] taskId: 1 12-11 08:47:40.783 DEBUG [HeadlessTask onHeadlessEvent] 💀 event: motionchange 12-11 08:47:40.788 DEBUG [HeadlessTask$2 onHeadlessJsTaskStart] taskId: 2 12-11 08:47:40.789 INFO [TSLocationManager d] 🔴 Location-services: OFF 12-11 08:47:40.793 INFO [TSLocationManager requestLocationUpdates] 🎾 Location-services: ON 12-11 08:47:40.795 DEBUG [TSConfig translateDesiredAccuracy] translateDesiredAccuracy (true): -1 12-11 08:47:40.809 DEBUG [AbstractService f] ⚙️︎ GeofencingService.stopSelfResult(1): true 12-11 08:47:40.815 INFO [SQLiteLocationDAO persist] ✅ INSERT: b158cef8-5236-429c-b5e0-f35692531f5d 12-11 08:47:40.923 INFO [ActivityRecognitionService start] 🎾 Start motion-activity updates 12-11 08:47:40.928 DEBUG [AbstractService onDestroy] 🔴 GeofencingService stopped 12-11 08:47:41.040 DEBUG [TSSQLiteAppender$c run] ℹ️ Cleared logs older than 120 hours 12-11 08:47:41.403 DEBUG [HeadlessTask$2 onHeadlessJsTaskStart] taskId: 3 12-11 08:47:41.407 DEBUG [HeadlessTask$2 onHeadlessJsTaskStart] taskId: 4 12-11 08:47:41.413 DEBUG [HeadlessTask$2 onHeadlessJsTaskStart] taskId: 5 12-11 08:47:41.691 DEBUG [TSLog log] headless event name: location 12-11 08:47:41.698 DEBUG [HeadlessTask$2 onHeadlessJsTaskFinish] taskId: 1 12-11 08:47:41.700 DEBUG [TSLog log] headless event name: motionchange ```
iOS Logs ``` 2023-12-09 20:07:21.567 ℹ️-[TSConfig persist] 2023-12-09 20:07:31.517 🔴-[LocationManager stopUpdatingLocation] OFF 2023-12-09 20:07:51.525 🔵-[TSLocationManager endStartDetection] 2023-12-09 20:07:51.526 ✅-[BackgroundTaskManager stopBackgroundTask:]_block_invoke 72 OF ( 72 ) 2023-12-10 01:08:27.003 ℹ️-[TSLocationManager log:message:] Enter onActivity change event 2023-12-10 01:08:27.003 ℹ️-[TSLocationManager log:message:] [ACTIVITY CHANGE] - {"activity":"in_vehicle","confidence":66} 2023-12-10 01:08:27.023 ℹ️-[TSLocationManager locationManager:didUpdateLocations:] Manual stationary region exit detected (probably via significant location change) 2023-12-10 01:08:27.023 🔵-[TSLocationManager setPace:] 1 2023-12-10 01:08:27.023 ℹ️-[TSConfig persist] 2023-12-10 01:08:27.029 🎾-[TSLocationManager startUpdatingLocation] Location-services: ON 2023-12-10 01:08:27.049 ℹ️+[LocationAuthorization run:onCancel:] status: 3 2023-12-10 01:08:27.050 ✅-[TSLocationManager locationManager:didUpdateLocations:] Acquired motionchange position: <+48.78579967,+6.25408925> +/- 1414.00m (speed -1.00 mps / course -1.00) @ 10/12/2023, 01:08:27 Central European Standard Time 2023-12-10 01:08:27.050 🎾-[TSLocationManager startUpdatingLocation] Location-services: ON 2023-12-10 01:08:27.050 🔵-[TSLocationManager calculateMedianLocationAccuracy:] Median location accuracy: 9.1 2023-12-10 01:08:27.054 ✅-[TSLocationManager persistLocation:]_block_invoke INSERT: BDCDAACB-B148-41DE-B655-671937FF78B2 ```
christocracy commented 10 months ago

It's completely in the hands of the OS to inform the plug-in when the stationary geofence has been exit (or on Android which is additionally informed by the motion api),

It can take longer than 200 meters depending on the environment (eg rural vs urban). 200 meters is only typical.

christocracy commented 10 months ago

You are free to manually engage location tracking using the method .changePace(true).

paultranvan commented 10 months ago

Thanks for the quick response @christocracy. .changePace is not really an option for us, because we do not want to force the user to manually starts a trip, we want to automatically detect it.

It's completely in the hands of the OS to inform the plug-in

Indeed, but is there any way to force the OS to "wake-up", so it can inform the plug-in faster?

And just to be sure it is truly an OS issue, did you also experience this behavior on some of your devices?

christocracy commented 10 months ago

but is there any way to force the OS to "wake-up", so it can inform the plug-in faster?

No. Your app is completely suspended in the background while in the stationary state, like a laptop with the screen closed. It's up to the OS to "lift the screen" on the laptop to awaken your app.

christocracy commented 10 months ago

is there any way to force the OS to "wake-up"

This is precisely what the "stationary geofence" is for (a geofence around the last known position"), the exit of which causes the OS to reawaken your app, causing the plug-in to turn on location-services and begins tracking (Android adds an additional listener on the motion api).

Until the OS reawakens your app, your app is frozen in ice. There is no code running.

Make sure the user does not disable wifi, since the OS uses wifi signals to evaluate geofences. Without wifi signals, the OS only has cell-tower change events to evaluate geofences, typically requiring >= 1km of movement.

paultranvan commented 10 months ago

Make sure the user does not disable wifi, since the OS uses wifi signals to evaluate geofences. Without wifi signals, the OS only has cell-tower change events to evaluate geofences, typically requiring >= 1km of movement.

That's quite interesting, I didn't know that. But does that mean the GPS is not used at all to evalute geofence? What if the user has no network enabled at all? The geofence exit will never be detected?

christocracy commented 10 months ago

But does that mean the GPS is not used at all to evalute geofence?

Correct. The OS passively monitors geofences using wifi.

paultranvan commented 10 months ago

Ok thanks, that's good to know. I guess there is not much we can do about it, so let's close the issue