From 84e22789c8ebd90d635d063545b5ef24cd3d59b4 Mon Sep 17 00:00:00 2001 From: Michelle Tang Date: Thu, 9 Jan 2025 09:46:26 -0500 Subject: [PATCH] Add wake lock when linking devices. --- .../linkdevice/AddLinkDeviceFragment.kt | 12 ++++- .../linkdevice/LinkDeviceFragment.kt | 17 +++++++ .../linkdevice/LinkDeviceViewModel.kt | 10 ++++ .../linkdevice/LinkDeviceWakeLock.kt | 49 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceWakeLock.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/AddLinkDeviceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/AddLinkDeviceFragment.kt index 1189abf605..63f33f4ec8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/AddLinkDeviceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/AddLinkDeviceFragment.kt @@ -28,6 +28,7 @@ import org.signal.core.ui.SignalPreview import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.compose.ComposeFragment import org.thoughtcrime.securesms.permissions.Permissions +import org.thoughtcrime.securesms.util.VibrateUtil import org.thoughtcrime.securesms.util.navigation.safeNavigate /** @@ -35,6 +36,10 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate */ class AddLinkDeviceFragment : ComposeFragment() { + companion object { + private const val VIBRATE_DURATION_MS = 50 + } + private val viewModel: LinkDeviceViewModel by activityViewModels() @OptIn(ExperimentalPermissionsApi::class) @@ -59,7 +64,12 @@ class AddLinkDeviceFragment : ComposeFragment() { hasPermissions = cameraPermissionState.status.isGranted, onRequestPermissions = { askPermissions() }, onShowFrontCamera = { viewModel.showFrontCamera() }, - onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) }, + onQrCodeScanned = { data -> + if (VibrateUtil.isHapticFeedbackEnabled(requireContext())) { + VibrateUtil.vibrate(requireContext(), VIBRATE_DURATION_MS) + } + viewModel.onQrCodeScanned(data) + }, onQrCodeApproved = { navController.popBackStack() viewModel.addDevice(shouldSync = false) diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt index 18ecc3477f..b9e41f3164 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt @@ -88,6 +88,7 @@ class LinkDeviceFragment : ComposeFragment() { private val viewModel: LinkDeviceViewModel by activityViewModels() private lateinit var biometricAuth: BiometricDeviceAuthentication private lateinit var biometricDeviceLockLauncher: ActivityResultLauncher + private lateinit var linkDeviceWakeLock: LinkDeviceWakeLock override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -110,6 +111,8 @@ class LinkDeviceFragment : ComposeFragment() { BiometricPrompt(requireActivity(), BiometricAuthenticationListener()), promptInfo ) + + linkDeviceWakeLock = LinkDeviceWakeLock(requireActivity()) } override fun onPause() { @@ -123,6 +126,20 @@ class LinkDeviceFragment : ComposeFragment() { val navController: NavController by remember { mutableStateOf(findNavController()) } val context = LocalContext.current + LaunchedEffect(state.dialogState) { + when (state.dialogState) { + DialogState.None, is DialogState.SyncingFailed, DialogState.SyncingTimedOut -> { + Log.i(TAG, "Releasing wake lock for linked device") + linkDeviceWakeLock.release() + } + DialogState.SyncingMessages, DialogState.Linking -> { + Log.i(TAG, "Acquiring wake lock for linked device") + linkDeviceWakeLock.acquire() + } + DialogState.Unlinking -> Unit + } + } + LaunchedEffect(state.oneTimeEvent) { when (val event = state.oneTimeEvent) { LinkDeviceSettingsState.OneTimeEvent.None -> { diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt index c76f19dd12..50658bd80e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt @@ -222,6 +222,11 @@ class LinkDeviceViewModel : ViewModel() { if (result !is LinkDeviceResult.Success) { Log.w(TAG, "[addDeviceWithSync] Unable to link device $result") + _state.update { + it.copy( + dialogState = DialogState.None + ) + } return } @@ -287,6 +292,11 @@ class LinkDeviceViewModel : ViewModel() { if (result !is LinkDeviceResult.Success) { Log.w(TAG, "Unable to link device $result") + _state.update { + it.copy( + dialogState = DialogState.None + ) + } return } diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceWakeLock.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceWakeLock.kt new file mode 100644 index 0000000000..d9c92bcd0e --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceWakeLock.kt @@ -0,0 +1,49 @@ +package org.thoughtcrime.securesms.linkdevice + +import android.os.PowerManager +import androidx.activity.ComponentActivity +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import org.thoughtcrime.securesms.util.WakeLockUtil +import kotlin.time.Duration.Companion.minutes + +/** + * Holds on to and manages a wake-lock when linking a device. + */ +class LinkDeviceWakeLock( + private val activity: ComponentActivity +) : DefaultLifecycleObserver { + + companion object { + private val TIMEOUT = 10.minutes.inWholeMilliseconds + } + + private var wakeLock: PowerManager.WakeLock? = null + + init { + activity.lifecycle.addObserver(this) + } + + fun acquire() { + synchronized(this) { + if (wakeLock?.isHeld == true) { + return + } + + wakeLock = WakeLockUtil.acquire(activity, PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TIMEOUT, "linkDevice") + } + } + + fun release() { + synchronized(this) { + if (wakeLock?.isHeld == true) { + wakeLock?.release() + wakeLock = null + } + } + } + + override fun onPause(owner: LifecycleOwner) { + release() + } +}