Skip to content

Commit 25dbe81

Browse files
committed
Avoid haptics while app in background
1 parent f72978b commit 25dbe81

2 files changed

Lines changed: 22 additions & 5 deletions

File tree

app/src/main/java/com/sameerasw/airsync/presentation/ui/screens/AirSyncMainScreen.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import androidx.compose.material.icons.filled.QrCodeScanner
3939
import androidx.compose.material.icons.filled.LinkOff
4040
import androidx.compose.material.icons.outlined.Phonelink
4141
import androidx.compose.material.icons.outlined.Settings
42+
import androidx.lifecycle.compose.LocalLifecycleOwner
4243
import androidx.lifecycle.viewmodel.compose.viewModel
4344
import com.sameerasw.airsync.presentation.viewmodel.AirSyncViewModel
4445
import com.sameerasw.airsync.utils.ClipboardSyncManager
@@ -95,6 +96,7 @@ fun AirSyncMainScreen(
9596
val deviceInfo by viewModel.deviceInfo.collectAsState()
9697
val scope = rememberCoroutineScope()
9798
val haptics = LocalHapticFeedback.current
99+
val lifecycle = LocalLifecycleOwner.current.lifecycle
98100
val connectScrollState = rememberScrollState()
99101
val settingsScrollState = rememberScrollState()
100102
var hasProcessedQrDialog by remember { mutableStateOf(false) }
@@ -306,8 +308,7 @@ fun AirSyncMainScreen(
306308
// Start/stop loading haptics when connecting
307309
LaunchedEffect(uiState.isConnecting) {
308310
if (uiState.isConnecting) {
309-
loadingHapticsJob?.cancel()
310-
loadingHapticsJob = HapticUtil.startLoadingHaptics(haptics)
311+
loadingHapticsJob = HapticUtil.startLoadingHaptics(haptics, lifecycle)
311312
} else {
312313
loadingHapticsJob?.cancel()
313314
loadingHapticsJob = null

app/src/main/java/com/sameerasw/airsync/utils/HapticUtil.kt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineScope
88
import kotlinx.coroutines.Dispatchers
99
import kotlinx.coroutines.launch
1010
import kotlinx.coroutines.isActive
11+
import androidx.lifecycle.Lifecycle
1112

1213
object HapticUtil {
1314
/**
@@ -49,12 +50,27 @@ object HapticUtil {
4950
/**
5051
* Start repeating haptic ticks for loading states
5152
* Returns a Job that can be cancelled to stop the haptics
53+
*
54+
* If a lifecycle is provided, haptics will only fire while the lifecycle
55+
* is at least STARTED (i.e. the app/screen is in foreground). This prevents
56+
* haptics from triggering while the app is backgrounded.
5257
*/
53-
fun startLoadingHaptics(haptics: HapticFeedback?): Job {
58+
fun startLoadingHaptics(haptics: HapticFeedback?, lifecycle: Lifecycle? = null): Job {
5459
return CoroutineScope(Dispatchers.Main).launch {
5560
while (isActive) {
56-
performLightTick(haptics)
57-
delay(200) // 5 times per second
61+
try {
62+
val shouldRun = lifecycle?.currentState?.isAtLeast(Lifecycle.State.STARTED) ?: true
63+
if (shouldRun) {
64+
performLightTick(haptics)
65+
delay(200) // 5 times per second
66+
} else {
67+
// Backoff while app is backgrounded; poll until it becomes STARTED again
68+
delay(200)
69+
}
70+
} catch (_: Exception) {
71+
// swallow any exceptions from lifecycle or haptics and continue
72+
delay(200)
73+
}
5874
}
5975
}
6076
}

0 commit comments

Comments
 (0)