@@ -2,8 +2,11 @@ package com.sasakulab.yure_android_client
22
33import android.content.Context
44import android.content.Intent
5+ import android.net.Uri
56import android.os.Build
67import android.os.Bundle
8+ import android.os.PowerManager
9+ import android.provider.Settings
710import androidx.activity.ComponentActivity
811import androidx.activity.compose.setContent
912import androidx.activity.enableEdgeToEdge
@@ -63,10 +66,12 @@ class MainActivity : ComponentActivity() {
6366 serverUrl = getServerUrl(),
6467 bufferSize = getBufferSize(),
6568 sensorData = sensorDataBuffer,
69+ isBatteryOptimized = ! isBatteryOptimizationIgnored(),
6670 onStartClick = { startSharing() },
6771 onStopClick = { stopSharing() },
6872 onServerUrlChanged = { saveServerUrl(it) },
6973 onBufferSizeChanged = { saveBufferSize(it) },
74+ onRequestBatteryOptimization = { requestIgnoreBatteryOptimization() },
7075 modifier = Modifier .padding(innerPadding)
7176 )
7277 }
@@ -115,6 +120,27 @@ class MainActivity : ComponentActivity() {
115120 prefs.edit().putInt(" bufferSize" , size).apply ()
116121 }
117122
123+ // Check if battery optimization is ignored
124+ private fun isBatteryOptimizationIgnored (): Boolean {
125+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
126+ val powerManager = getSystemService(Context .POWER_SERVICE ) as PowerManager
127+ return powerManager.isIgnoringBatteryOptimizations(packageName)
128+ }
129+ return true
130+ }
131+
132+ // Request to ignore battery optimization
133+ private fun requestIgnoreBatteryOptimization () {
134+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
135+ if (! isBatteryOptimizationIgnored()) {
136+ val intent = Intent (Settings .ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS ).apply {
137+ data = Uri .parse(" package:$packageName " )
138+ }
139+ startActivity(intent)
140+ }
141+ }
142+ }
143+
118144 // Start to share accelerometer data
119145 private fun startSharing () {
120146 val serviceIntent = Intent (this , YureSensorService ::class .java).apply {
@@ -161,10 +187,12 @@ fun YureScreen(
161187 serverUrl : String ,
162188 bufferSize : Int ,
163189 sensorData : List <AccelerationData >,
190+ isBatteryOptimized : Boolean ,
164191 onStartClick : () -> Unit ,
165192 onStopClick : () -> Unit ,
166193 onServerUrlChanged : (String ) -> Unit ,
167194 onBufferSizeChanged : (Int ) -> Unit ,
195+ onRequestBatteryOptimization : () -> Unit ,
168196 modifier : Modifier = Modifier
169197) {
170198 var showServerUrlDialog by remember { mutableStateOf(false ) }
@@ -235,6 +263,40 @@ fun YureScreen(
235263
236264 Spacer (modifier = Modifier .height(32 .dp))
237265
266+ // Battery optimization warning
267+ if (isBatteryOptimized) {
268+ Card (
269+ modifier = Modifier .fillMaxWidth(),
270+ colors = CardDefaults .cardColors(
271+ containerColor = MaterialTheme .colorScheme.errorContainer
272+ )
273+ ) {
274+ Column (
275+ modifier = Modifier .padding(16 .dp)
276+ ) {
277+ Text (
278+ text = " Battery Optimization Enabled" ,
279+ style = MaterialTheme .typography.titleSmall,
280+ color = MaterialTheme .colorScheme.onErrorContainer
281+ )
282+ Spacer (modifier = Modifier .height(8 .dp))
283+ Text (
284+ text = " Background operation may stop after hours. Please disable battery optimization for continuous operation." ,
285+ style = MaterialTheme .typography.bodySmall,
286+ color = MaterialTheme .colorScheme.onErrorContainer
287+ )
288+ Spacer (modifier = Modifier .height(8 .dp))
289+ Button (
290+ onClick = onRequestBatteryOptimization,
291+ modifier = Modifier .fillMaxWidth()
292+ ) {
293+ Text (" Disable Battery Optimization" )
294+ }
295+ }
296+ }
297+ Spacer (modifier = Modifier .height(16 .dp))
298+ }
299+
238300 Button (
239301 onClick = { showServerUrlDialog = true },
240302 enabled = ! isSharing,
0 commit comments