summaryrefslogtreecommitdiff
path: root/android-app/app/src
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-19 22:00:37 +0000
committerClaude <noreply@anthropic.com>2026-05-19 22:00:37 +0000
commit48ae3b0225cb1a79539711be3a70cbd630c53638 (patch)
treedb254c5464e874f59cb93660ebef1b4949fa6054 /android-app/app/src
parentbbfcb667d9510e604676ac92cecc69f9bc39e440 (diff)
Reduce location resource usage: economy mode by default, lifecycle throttling
- Start LocationService at ECONOMY (5 s, PRIORITY_BALANCED_POWER_ACCURACY) instead of FULL (1 Hz, PRIORITY_HIGH_ACCURACY); promote to FULL only while a track is actively recording and demote back when recording stops - Use PRIORITY_BALANCED_POWER_ACCURACY for ECONOMY and ANCHOR_WATCH modes so the GPS chip idles and network/passive sources handle light-duty fixes - Add ACTION_START_ECONOMY / ACTION_START_FULL intents so MainActivity can drive mode transitions from lifecycle callbacks - onPause: drop to ECONOMY if not recording or anchor-watching; onResume: restore the appropriate mode so the first visible frame has a fresh rate - Stop-anchor-watch now returns to ECONOMY instead of FULL (anchor drop rarely coincides with active track recording) - Remove ACCESS_BACKGROUND_LOCATION from manifest — the foreground service with foregroundServiceType="location" already covers background access - Add 5 m minimum-distance filter to DeviceGpsProvider so stationary devices don't generate spurious location callbacks https://claude.ai/code/session_01YUbuZNDAoLea4cf9UGQ9qn
Diffstat (limited to 'android-app/app/src')
-rw-r--r--android-app/app/src/main/AndroidManifest.xml1
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt16
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt37
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt3
4 files changed, 50 insertions, 7 deletions
diff --git a/android-app/app/src/main/AndroidManifest.xml b/android-app/app/src/main/AndroidManifest.xml
index a10d503..5090190 100644
--- a/android-app/app/src/main/AndroidManifest.xml
+++ b/android-app/app/src/main/AndroidManifest.xml
@@ -3,7 +3,6 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt b/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt
index 18e0907..015e334 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/LocationService.kt
@@ -236,8 +236,8 @@ class LocationService : Service() {
ACTION_START_FOREGROUND_SERVICE -> {
startForeground(NOTIFICATION_ID, createNotification())
serviceScope.launch {
- _currentPowerMode.emit(PowerMode.FULL)
- startLocationUpdatesInternal(PowerMode.FULL)
+ _currentPowerMode.emit(PowerMode.ECONOMY)
+ startLocationUpdatesInternal(PowerMode.ECONOMY)
}
barometerSensorManager.start()
val flags = (application as NavApplication).featureFlags
@@ -251,6 +251,8 @@ class LocationService : Service() {
nmeaStreamManager.stop()
stopSelf()
}
+ ACTION_START_ECONOMY -> setPowerMode(PowerMode.ECONOMY)
+ ACTION_START_FULL -> setPowerMode(PowerMode.FULL)
ACTION_START_ANCHOR_WATCH -> {
val radius = intent.getDoubleExtra(EXTRA_WATCH_RADIUS, AnchorWatchState.DEFAULT_WATCH_CIRCLE_RADIUS_METERS)
serviceScope.launch {
@@ -260,7 +262,7 @@ class LocationService : Service() {
}
ACTION_STOP_ANCHOR_WATCH -> {
stopAnchorWatch()
- setPowerMode(PowerMode.FULL)
+ setPowerMode(PowerMode.ECONOMY)
}
ACTION_UPDATE_WATCH_RADIUS -> {
val radius = intent.getDoubleExtra(EXTRA_WATCH_RADIUS, AnchorWatchState.DEFAULT_WATCH_CIRCLE_RADIUS_METERS)
@@ -297,7 +299,11 @@ class LocationService : Service() {
@SuppressLint("MissingPermission")
private fun startLocationUpdatesInternal(powerMode: PowerMode) {
- val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, powerMode.gpsUpdateIntervalMillis)
+ val priority = if (powerMode == PowerMode.FULL)
+ Priority.PRIORITY_HIGH_ACCURACY
+ else
+ Priority.PRIORITY_BALANCED_POWER_ACCURACY
+ val locationRequest = LocationRequest.Builder(priority, powerMode.gpsUpdateIntervalMillis)
.setMinUpdateIntervalMillis(powerMode.gpsUpdateIntervalMillis / 2)
.build()
fusedLocationClient.requestLocationUpdates(
@@ -378,6 +384,8 @@ class LocationService : Service() {
companion object {
const val ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE"
const val ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE"
+ const val ACTION_START_ECONOMY = "ACTION_START_ECONOMY"
+ const val ACTION_START_FULL = "ACTION_START_FULL"
const val ACTION_START_ANCHOR_WATCH = "ACTION_START_ANCHOR_WATCH"
const val ACTION_STOP_ANCHOR_WATCH = "ACTION_STOP_ANCHOR_WATCH"
const val ACTION_UPDATE_WATCH_RADIUS = "ACTION_UPDATE_WATCH_RADIUS"
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
index 8609456..05dbf12 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
@@ -112,6 +112,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
private val viewModel: MainViewModel by viewModels()
private var pendingServiceStart = false
+ private var serviceStarted = false
override fun onResume() {
super.onResume()
@@ -119,9 +120,17 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
if (pendingServiceStart) {
pendingServiceStart = false
startServices()
+ } else {
+ restoreLocationMode()
}
}
+ override fun onPause() {
+ super.onPause()
+ if (!NavApplication.isTesting) mapView?.onPause()
+ throttleLocationIfIdle()
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
MapLibre.getInstance(this)
@@ -449,6 +458,25 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
finishAffinity()
}
+ private fun locationServiceIntent(action: String) =
+ Intent(this, LocationService::class.java).apply { this.action = action }
+
+ /** Drop to economy rate when the app goes to the background and nothing needs precision. */
+ private fun throttleLocationIfIdle() {
+ if (!serviceStarted) return
+ if (!viewModel.isRecording.value && !LocationService.anchorWatchState.value.isActive) {
+ startService(locationServiceIntent(LocationService.ACTION_START_ECONOMY))
+ }
+ }
+
+ /** On return to foreground: restore full accuracy if recording, otherwise economy. */
+ private fun restoreLocationMode() {
+ if (!serviceStarted) return
+ val action = if (viewModel.isRecording.value) LocationService.ACTION_START_FULL
+ else LocationService.ACTION_START_ECONOMY
+ startService(locationServiceIntent(action))
+ }
+
override fun onActivateMob() {
lifecycleScope.launch {
LocationService.locationFlow.firstOrNull()?.let { gpsData ->
@@ -519,6 +547,7 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
}
private fun startServices() {
+ serviceStarted = true
val intent = Intent(this, LocationService::class.java).apply {
action = LocationService.ACTION_START_FOREGROUND_SERVICE
}
@@ -658,6 +687,13 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
private fun observeDataSources() {
startThermalMonitoring()
+ lifecycleScope.launch {
+ viewModel.isRecording.collect { recording ->
+ val action = if (recording) LocationService.ACTION_START_FULL
+ else LocationService.ACTION_START_ECONOMY
+ startService(locationServiceIntent(action))
+ }
+ }
var conditionsLoaded = false
lifecycleScope.launch {
LocationService.locationFlow.collect { gpsData ->
@@ -801,7 +837,6 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
}
override fun onStart() { super.onStart(); if (!NavApplication.isTesting) mapView?.onStart() }
- override fun onPause() { super.onPause(); if (!NavApplication.isTesting) mapView?.onPause() }
override fun onStop() { super.onStop(); if (!NavApplication.isTesting) mapView?.onStop() }
override fun onDestroy() { super.onDestroy(); if (!NavApplication.isTesting) mapView?.onDestroy(); stopThermalAlarm() }
override fun onLowMemory() { super.onLowMemory(); if (!NavApplication.isTesting) mapView?.onLowMemory() }
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt b/android-app/app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt
index f2a4e59..a8d46e4 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt
@@ -56,7 +56,7 @@ class DeviceGpsProvider(
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
updateIntervalMs,
- 0f,
+ MIN_UPDATE_DISTANCE_METERS,
locationListener,
Looper.getMainLooper()
)
@@ -83,5 +83,6 @@ class DeviceGpsProvider(
companion object {
private const val FIX_LOST_TIMEOUT_MS = 10_000L
+ private const val MIN_UPDATE_DISTANCE_METERS = 5f
}
}