From 48ae3b0225cb1a79539711be3a70cbd630c53638 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 22:00:37 +0000 Subject: Reduce location resource usage: economy mode by default, lifecycle throttling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- android-app/app/src/main/AndroidManifest.xml | 1 - .../main/kotlin/org/terst/nav/LocationService.kt | 16 +++++++--- .../src/main/kotlin/org/terst/nav/MainActivity.kt | 37 +++++++++++++++++++++- .../kotlin/org/terst/nav/gps/DeviceGpsProvider.kt | 3 +- 4 files changed, 50 insertions(+), 7 deletions(-) (limited to 'android-app/app/src/main') 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 @@ - 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 } } -- cgit v1.2.3