Closed YaLazreq closed 1 month ago
I do not have any sort of problem with the demo app tracking me everywhere I go, regardless how long it stops (length of time stopped does not matter).
start by consulting https://dontkillmyapp.com
@christocracy Ok, I think I understand the logic. In your /example
folder, I was trying the Hello World app. I need some clarification:
When you set bg.BackgroundGeolocation.ready(CONFIG)
, you don't call .start()
. You only call it when you press the PLAY button, and it switches from green to red. The thing is that I don't understand changePace(). Why use changePace()
when you already have .start()
?
I understand that changePace()
starts aggressive location tracking, but I don't understand the difference between it and .start()
. Is changePace(true)
using the battery-conscious motion-detection intelligence, or does it just track without pause?
For more context, let's take a cab. When the cab presses the start button, it is now online (so .start()
was called). For example, when the cab accepts a ride, would we then call changePace(true)
to ensure we have continuous access to the location during the ride?
That's how I understand it.
When i try both, i have the same result, i just notice some change on battery-conscious that why i need your answer. Thanks in advance chris.
[CODE SAMPLE]
bg.BackgroundGeolocation.ready(bg.Config(
reset: true,
debug: true,
logLevel: bg.Config.LOG_LEVEL_VERBOSE,
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
distanceFilter: 10.0,
backgroundPermissionRationale: bg.PermissionRationale(
title:
"Allow {applicationName} to access this device's location even when the app is closed or not in use.",
message:
"This app collects location data to enable recording your trips to work and calculate distance-travelled.",
positiveAction: 'Change to "{backgroundPermissionOptionLabel}"',
negativeAction: 'Cancel'),
url: "${ENV.TRACKER_HOST}/api/locations",
authorization: bg.Authorization(
// <-- demo server authenticates with JWT
strategy: bg.Authorization.STRATEGY_JWT,
accessToken: token.accessToken,
refreshToken: token.refreshToken,
refreshUrl: "${ENV.TRACKER_HOST}/api/refresh_token",
refreshPayload: {'refresh_token': '{refreshToken}'}),
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true))
.then((bg.State state) {
print("[ready] ${state.toMap()}");
bg.BackgroundGeolocation.start().then((bg.State state) {
print('[start] success $state');
setState(() {
_enabled = state.enabled;
_isMoving = state.isMoving!;
});
}).catchError((error) {
print('[start] ERROR: $error');
});
setState(() {
_enabled = state.enabled;
_isMoving = state.isMoving!;
});
}).catchError((error) {
print('[ready] ERROR: $error');
});
void _onClickEnable(enabled) {
if (enabled) {
// Reset odometer.
bg.BackgroundGeolocation.start().then((bg.State state) {
print('[start] success $state');
setState(() {
_enabled = state.enabled;
_isMoving = state.isMoving!;
});
}).catchError((error) {
print('[start] ERROR: $error');
});
} else {
bg.BackgroundGeolocation.stop().then((bg.State state) {
print('[stop] success: $state');
setState(() {
_enabled = state.enabled;
_isMoving = state.isMoving!;
});
});
}
}
// Manually toggle the tracking state: moving vs stationary
void _onClickChangePace() {
setState(() {
_isMoving = !_isMoving;
});
print("[onClickChangePace] -> $_isMoving");
bg.BackgroundGeolocation.changePace(_isMoving).then((bool isMoving) {
print('[changePace] success $isMoving');
}).catchError((e) {
print('[changePace] ERROR: ' + e.code.toString());
});
}
If the plug-in were an electronic device, such as a stereo receiver:
the plug-in automatically calls .changePace upon itself when the device is detected to be moving / stationary.
Executing .changePace manually toggles the tracking state.
read the wiki here “Philosophy of Operation” for more information.
Ok i understand now, thanks a lot!
So we can use .start()
without changePace()
write? we only need to put the .start() call into .ready()
callback ?
As I said above, the plug-in automatically calls .changePace upon itself when the device is detected to be moving.
a jogging app would manually call .changePace(true) (after calling .start()) with a [Start Workout] button.
Ok thanks @christocracy . After waiting to switch stationnary i receive these logs:
I/TSLocationManager(31055): ╔═════════════════════════════════════════════
I/TSLocationManager(31055): ║ ⏰ OneShot event fired: STOP_TIMEOUT
I/TSLocationManager(31055): ╠═════════════════════════════════════════════
D/TSLocationManager(31055): [c.t.l.adapter.TSConfig e] ℹ️ Persist config, dirty: [isMoving]
I/TSLocationManager(31055): [c.t.l.service.HeartbeatService stop]
I/TSLocationManager(31055): 🔴 Stop heartbeat
I/TSLocationManager(31055): [c.t.l.l.TSLocationManager d]
I/TSLocationManager(31055): 🔴 Location-services: OFF
I/TSLocationManager(31055): [c.t.l.service.TrackingService changePace]
I/TSLocationManager(31055): 🔵 setPace: true → false
D/EGL_emulation(31055): app_time_stats: avg=14.78ms min=4.70ms max=42.47ms count=52
I/TSLocationManager(31055): [c.t.l.l.TSLocationManager a]
I/TSLocationManager(31055): ╔═════════════════════════════════════════════
I/TSLocationManager(31055): ║ motionchange LocationResult: 2 (481ms old)
I/TSLocationManager(31055): ╠═════════════════════════════════════════════
I/TSLocationManager(31055): ╟─ 📍 Location[fused 48.871459,2.322279 hAcc=5.0 et=+8h32m42s429ms alt=0.0 vAcc=0.5 vel=3.9321966 sAcc=0.5 bear=155.0677 bAcc=30.0], time: 1729204342579
I/TSLocationManager(31055): [c.t.l.l.TSLocationManager onSingleLocationResult]
I/TSLocationManager(31055): 🔵 Acquired motionchange position, isMoving: false
D/TSLocationManager(31055): [c.t.l.l.TSLocationManager a] Median accuracy: 5.0
I/flutter (31055): ======================> ✅ ✅ ✅ LAT: 48.8714587, LNG: 2.3222791
D/TSLocationManager(31055): [c.t.l.g.TSGeofenceManager startMonitoringStationaryRegion]
D/TSLocationManager(31055): 🎾 Start monitoring stationary region (radius: 150.0m 48.8714587,2.3222791 hAcc=5.0)
I/flutter (31055): ======================> ✅ ✅ ✅ LAT: 48.8714587, LNG: 2.3222791
I/TSLocationManager(31055): [c.t.l.d.s.SQLiteLocationDAO persist]
I/TSLocationManager(31055): ✅ INSERT: d02cb8e2-6b23-4f8b-a974-82bf41adf342
D/TSLocationManager(31055): [c.t.l.service.AbstractService a]
D/TSLocationManager(31055): 🎾 motionchange [TrackingService startId: 112, eventCount: 1]
I/TSLocationManager(31055): [c.t.l.service.TrackingService k]
I/TSLocationManager(31055): ╔═════════════════════════════════════════════
I/TSLocationManager(31055): ║ TrackingService motionchange: false
I/TSLocationManager(31055): ╠═════════════════════════════════════════════
D/TSLocationManager(31055): [c.t.l.service.AbstractService a]
D/TSLocationManager(31055): ⚙️︎ FINISH [TrackingService startId: 112, eventCount: 0, sticky: false]
D/TSLocationManager(31055): [c.t.l.service.AbstractService f]
D/TSLocationManager(31055): ⚙️︎ TrackingService.stopSelfResult(112): true
D/TSLocationManager(31055): [c.t.l.service.AbstractService onDestroy]
D/TSLocationManager(31055): 🔴 TrackingService stopped
This is good, because it was what i want to try. As you can see, it says that the app starts monitoring a stationary region around the last known location (with a 150-meter radius),. But when i restart location from the stationary positition, to go to the Eiffel Tour, the location didn't restart.
This is exaclty the same problem i had i my previous case. Everytime the location tracking is stopped, it don't want to restart after exit the 150m radius..
I only use the configuration below, but everything looks okay. I don't use changePace()
, i only use .start()
. Do you have some advice ?
Future _initPlatformState() async {
// 1. Listen to events (See docs for all 12 available events).
// bg.BackgroundGeolocation.onLocation(_onLocation, _onLocationError);
// bg.BackgroundGeolocation.onMotionChange(_onMotionChange);
// bg.BackgroundGeolocation.onActivityChange(_onActivityChange);
// bg.BackgroundGeolocation.onProviderChange(_onProviderChange);
// bg.BackgroundGeolocation.onConnectivityChange(_onConnectivityChange);
// bg.BackgroundGeolocation.onHttp(_onHttp);
// bg.BackgroundGeolocation.onAuthorization(_onAuthorization);
// 2. Configure the plugin
bg.BackgroundGeolocation.ready(bg.Config(
reset: true,
debug: true,
logLevel: bg.Config.LOG_LEVEL_VERBOSE,
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
distanceFilter: 10.0,
isMoving: true,
stopOnTerminate: true,
startOnBoot: false,
enableHeadless: false))
.then((bg.State state) {
print("================> 🟢 [ready] ");
bg.BackgroundGeolocation.start().then((bg.State state) {
print(
'================> 🟢🟢 [start] success : Enabled? :${state.enabled} | IsMoving? :${state.isMoving}');
setState(() {
// _enabled = state.enabled;
// _isMoving = state.isMoving!;
});
}).catchError((error) {
print('===============> 🔴 [start] ERROR: $error');
});
setState(() {
// _enabled = state.enabled;
// _isMoving = state.isMoving!;
});
}).catchError((error) {
print('================> [ready] ERROR: $error');
});
}
Test on Medium Phone - Android 15 API35 | arm64
It’s well-known that Android geofences almost never work in the emulator with simulated location.
Yes i just notice that, everything good in my side now 👍🏽
@christocracy
Your Environment
flutter doctor
):Expected Behavior
ANDROID
In my application, when the user is working, he presses a button. This button starts the localization. I want to stop the location service when the user is stopped and restart the service when the user is back on the road, until he clicks the button again to log out.
Actual Behavior
I was testing the lib to start when the user click on a button 'START'. But I ran into a problem. When I press the start button, I call the changePace(true) function. After 1min on stationary mode, the device has not detected any movement so it trigger a scheduled Oneshot.
A Scheduled OneShot: STOP_TIMEOUT in 300000ms (5min) is triggered.
After these 5min, if the device is still detected as 'stationary', then all services are disabled (heartbeat, TrackingService) and the Pace is set to false.
The problem is that if I decide to move after these 5min, nothing is triggered anymore. It's as if the lib was disabled. Would you know how to fix this?
What happens instead is that the lib does not restart as it should. In an emergency situation this is problematic.
Also what is the difference between .start() and .changePace(true).
Steps to Reproduce
For test:
Context
I was trying to restart localization after a long period of inactivity.
Debug logs
Logs
**AFTER 1 MIN OF INACTIVITY** ``` D/TSLocationManager(21701): 🎾 start [ActivityRecognitionService startId: 1, eventCount: 1] D/TSLocationManager(21701): [c.t.l.s.ActivityRecognitionService a] D/TSLocationManager(21701): 🚘 ️DetectedActivity [type=STILL, confidence=100] D/TSLocationManager(21701): [c.t.l.service.AbstractService a] D/TSLocationManager(21701): 🎾 STOP_TIMEOUT [TrackingService startId: 38, eventCount: 1] D/TSLocationManager(21701): [c.t.l.service.AbstractService a] D/TSLocationManager(21701): ⚙️︎ FINISH [ActivityRecognitionService startId: 1, eventCount: 0, sticky: false] I/TSLocationManager(21701): [c.t.l.s.TSScheduleManager oneShot] I/TSLocationManager(21701): ⏰ Scheduled OneShot: STOP_TIMEOUT in 300000ms (jobID: 2059034116) I/TSLocationManager(21701): [c.t.l.s.TSScheduleManager cancelOneShot] I/TSLocationManager(21701): ⏰ Cancel OneShot: MOTION_ACTIVITY_CHECK D/TSLocationManager(21701): [c.t.l.service.AbstractService a] D/TSLocationManager(21701): ⚙️︎ FINISH [TrackingService startId: 38, eventCount: 0, sticky: true] D/TSLocationManager(21701): [c.t.l.service.AbstractService f] D/TSLocationManager(21701): ⚙️︎ ActivityRecognitionService.stopSelfResult(1): true D/TSLocationManager(21701): [c.t.l.service.AbstractService onDestroy] D/TSLocationManager(21701): 🔴 ActivityRecognitionService stopped ``` **AFTER 5MIN OF INACTIVITY (total deactivation of services)** ``` I/TSLocationManager(21701): ╔═════════════════════════════════════════════ I/TSLocationManager(21701): ║ ⏰ OneShot event fired: STOP_TIMEOUT I/TSLocationManager(21701): ╠═════════════════════════════════════════════ D/TSLocationManager(21701): [c.t.l.adapter.TSConfig e] ℹ️ Persist config, dirty: [isMoving] D/EGL_emulation(21701): app_time_stats: avg=2.32ms min=1.16ms max=4.09ms count=60 I/TSLocationManager(21701): [c.t.l.service.HeartbeatService stop] I/TSLocationManager(21701): 🔴 Stop heartbeat I/TSLocationManager(21701): [c.t.l.l.TSLocationManager d] I/TSLocationManager(21701): 🔴 Location-services: OFF I/TSLocationManager(21701): [c.t.l.service.TrackingService changePace] I/TSLocationManager(21701): 🔵 setPace: true → false I/TSLocationManager(21701): [c.t.l.l.TSLocationManager a] I/TSLocationManager(21701): ╔═════════════════════════════════════════════ I/TSLocationManager(21701): ║ motionchange LocationResult: 3 (65ms old) I/TSLocationManager(21701): ╠═════════════════════════════════════════════ I/TSLocationManager(21701): ╟─ 📍 Location[fused 48.833630,2.377956 hAcc=7.505 et=+8h51m4s476ms alt=0.0 vAcc=0.5 vel=15.360889 sAcc=0.5 bear=143.87012 bAcc=30.0], time: 1728762234391 I/TSLocationManager(21701): [c.t.l.l.TSLocationManager onSingleLocationResult] I/TSLocationManager(21701): 🔵 Acquired motionchange position, isMoving: false D/TSLocationManager(21701): [c.t.l.l.TSLocationManager a] Median accuracy: 5.0 I/TSLocationManager(21701): [c.t.l.d.s.SQLiteLocationDAO persist] I/TSLocationManager(21701): ✅ INSERT: 59943f8c-623c-4279-877c-827606b9b02d I/flutter (21701): 🟣 🟣 🟣 ====> LAT: 48.8336297, LNG: 2.3779561 I/flutter (21701): 🔴 🔴 🔴 [motionchange] - [Location {odometer: 34485.1015625, activity: {confidence: 100, type: still}, extras: {}, event: motionchange, battery: {level: 1.0, is_charging: false}, uuid: 59943f8c-623c-4279-877c-827606b9b02d, age: 71, coords: {altitude: 0.0, heading: 143.87, latitude: 48.8336297, accuracy: 7.51, heading_accuracy: 30.0, altitude_accuracy: 0.5, speed_accuracy: 0.5, speed: 15.36, age: 103, longitude: 2.3779561, ellipsoidal_altitude: 0.0}, is_moving: false, timestamp: 2024-10-12T19:43:54.391Z}] D/TSLocationManager(21701): [c.t.l.g.TSGeofenceManager startMonitoringStationaryRegion] D/TSLocationManager(21701): 🎾 Start monitoring stationary region (radius: 150.0m 48.8336297,2.3779561 hAcc=7.505) D/TSLocationManager(21701): [c.t.l.service.AbstractService a] D/TSLocationManager(21701): 🎾 motionchange [TrackingService startId: 74, eventCount: 1] I/TSLocationManager(21701): [c.t.l.service.TrackingService k] I/TSLocationManager(21701): ╔═════════════════════════════════════════════ I/TSLocationManager(21701): ║ TrackingService motionchange: false I/TSLocationManager(21701): ╠═════════════════════════════════════════════ D/TSLocationManager(21701): [c.t.l.service.AbstractService a] D/TSLocationManager(21701): ⚙️︎ FINISH [TrackingService startId: 74, eventCount: 0, sticky: false] D/TSLocationManager(21701): [c.t.l.service.AbstractService f] D/TSLocationManager(21701): ⚙️︎ TrackingService.stopSelfResult(74): true D/TSLocationManager(21701): [c.t.l.service.AbstractService onDestroy] D/TSLocationManager(21701): 🔴 TrackingService stopped D/EGL_emulation(21701): app_time_stats: avg=3.57ms min=1.11ms max=62.95ms count=58 V/MediaPlayer(21701): resetDrmState: mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false ```