diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ade3fe8381..bbb40da968 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -77,6 +77,14 @@ android:theme="@style/AppTheme.SplashScreen" tools:replace="android:allowBackup,android:supportsRtl"> + + Unit, onCancel: () -> Unit, - onRequestPasscode: () -> Unit + onRequestPasscode: () -> Unit, + onTooManyFailedAttempts: () -> Unit ): BiometricPrompt { val executor = ContextCompat.getMainExecutor(activity) @@ -43,10 +45,10 @@ object BiometricPromptUtils { override fun onAuthenticationError(errorCode: Int, errorString: CharSequence) { super.onAuthenticationError(errorCode, errorString) appLogger.i("$TAG errorCode is $errorCode and errorString is: $errorString") - if (errorCode == ERROR_NEGATIVE_BUTTON || errorCode == BiometricPrompt.ERROR_LOCKOUT) { - onRequestPasscode() - } else { - onCancel() + when (errorCode) { + ERROR_NEGATIVE_BUTTON -> onRequestPasscode() + ERROR_LOCKOUT -> onTooManyFailedAttempts() + else -> onCancel() } } @@ -76,7 +78,8 @@ object BiometricPromptUtils { fun AppCompatActivity.showBiometricPrompt( onSuccess: () -> Unit, onCancel: () -> Unit, - onRequestPasscode: () -> Unit + onRequestPasscode: () -> Unit, + onTooManyFailedAttempts: () -> Unit ) { val canAuthenticate = BiometricManager.from(this) .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) @@ -86,7 +89,8 @@ fun AppCompatActivity.showBiometricPrompt( activity = this, onSuccess = onSuccess, onCancel = onCancel, - onRequestPasscode = onRequestPasscode + onRequestPasscode = onRequestPasscode, + onTooManyFailedAttempts = onTooManyFailedAttempts ) val promptInfo = BiometricPromptUtils.createPromptInfo(this) biometricPrompt.authenticate(promptInfo) diff --git a/app/src/main/kotlin/com/wire/android/notification/MessageNotificationManager.kt b/app/src/main/kotlin/com/wire/android/notification/MessageNotificationManager.kt index 923e7b58a3..aab9c2f55c 100644 --- a/app/src/main/kotlin/com/wire/android/notification/MessageNotificationManager.kt +++ b/app/src/main/kotlin/com/wire/android/notification/MessageNotificationManager.kt @@ -37,6 +37,7 @@ import androidx.core.text.toSpannable import com.wire.android.R import com.wire.android.appLogger import com.wire.android.notification.NotificationConstants.getConversationNotificationId +import com.wire.android.ui.home.appLock.LockCodeTimeManager import com.wire.android.util.toBitmap import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.QualifiedID @@ -51,7 +52,8 @@ class MessageNotificationManager @Inject constructor( private val context: Context, private val notificationManagerCompat: NotificationManagerCompat, - private val notificationManager: NotificationManager + private val notificationManager: NotificationManager, + private val lockCodeTimeManager: LockCodeTimeManager ) { fun handleNotification(newNotifications: List, userId: QualifiedID, userName: String) { @@ -201,8 +203,9 @@ class MessageNotificationManager } is NotificationMessage.Comment -> { + val isAppLocked = lockCodeTimeManager.isAppLocked() setContentIntent(messagePendingIntent(context, conversation.id, userIdString)) - addAction(getActionReply(context, conversation.id, userIdString)) + addAction(getActionReply(context, conversation.id, userIdString, isAppLocked)) } is NotificationMessage.Knock -> { @@ -211,13 +214,15 @@ class MessageNotificationManager } is NotificationMessage.Text -> { + val isAppLocked = lockCodeTimeManager.isAppLocked() setContentIntent(messagePendingIntent(context, conversation.id, userIdString)) - addAction(getActionReply(context, conversation.id, userIdString)) + addAction(getActionReply(context, conversation.id, userIdString, isAppLocked)) } is NotificationMessage.ObfuscatedMessage -> { + val isAppLocked = lockCodeTimeManager.isAppLocked() setContentIntent(messagePendingIntent(context, conversation.id, userIdString)) - addAction(getActionReply(context, conversation.id, userIdString)) + addAction(getActionReply(context, conversation.id, userIdString, isAppLocked)) } is NotificationMessage.ObfuscatedKnock -> { @@ -226,8 +231,9 @@ class MessageNotificationManager } null -> { + val isAppLocked = lockCodeTimeManager.isAppLocked() setContentIntent(messagePendingIntent(context, conversation.id, userIdString)) - addAction(getActionReply(context, conversation.id, userIdString)) + addAction(getActionReply(context, conversation.id, userIdString, isAppLocked)) } } } @@ -470,7 +476,7 @@ class MessageNotificationManager val notification = setUpNotificationBuilder(context, userId).apply { setContentIntent(messagePendingIntent(context, conversationId, userIdString)) - addAction(getActionReply(context, conversationId, userIdString)) + addAction(getActionReply(context, conversationId, userIdString, false)) setWhen(System.currentTimeMillis()) diff --git a/app/src/main/kotlin/com/wire/android/notification/NotificationActions.kt b/app/src/main/kotlin/com/wire/android/notification/NotificationActions.kt index 01e30c3845..d118304ad0 100644 --- a/app/src/main/kotlin/com/wire/android/notification/NotificationActions.kt +++ b/app/src/main/kotlin/com/wire/android/notification/NotificationActions.kt @@ -30,15 +30,25 @@ import com.wire.android.R fun getActionFromOldOne(oldAction: Notification.Action) = NotificationCompat.Action.Builder(null, oldAction.title, oldAction.actionIntent).build() -fun getActionReply(context: Context, conversationId: String, userId: String?): NotificationCompat.Action { - val resultPendingIntent = replyMessagePendingIntent(context, conversationId, userId) +fun getActionReply( + context: Context, + conversationId: String, + userId: String?, + isAppLocked: Boolean +): NotificationCompat.Action { + return if (isAppLocked) { + val resultPendingIntent = messagePendingIntent(context, conversationId, userId) + NotificationCompat.Action.Builder(null, context.getString(R.string.notification_action_reply), resultPendingIntent) + .build() + } else { + val resultPendingIntent = replyMessagePendingIntent(context, conversationId, userId) + val remoteInput = RemoteInput.Builder(NotificationConstants.KEY_TEXT_REPLY).build() - val remoteInput = RemoteInput.Builder(NotificationConstants.KEY_TEXT_REPLY).build() - - return NotificationCompat.Action.Builder(null, context.getString(R.string.notification_action_reply), resultPendingIntent) - .addRemoteInput(remoteInput) - .setAllowGeneratedReplies(true) - .build() + NotificationCompat.Action.Builder(null, context.getString(R.string.notification_action_reply), resultPendingIntent) + .addRemoteInput(remoteInput) + .setAllowGeneratedReplies(true) + .build() + } } fun getOpenIncomingCallAction(context: Context, conversationId: String, userId: String) = getAction( diff --git a/app/src/main/kotlin/com/wire/android/ui/AppLockActivity.kt b/app/src/main/kotlin/com/wire/android/ui/AppLockActivity.kt new file mode 100644 index 0000000000..50dbd4aa1e --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/ui/AppLockActivity.kt @@ -0,0 +1,62 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import androidx.biometric.BiometricManager +import androidx.core.view.WindowCompat +import com.wire.android.appLogger +import com.wire.android.navigation.NavigationGraph +import com.wire.android.navigation.rememberNavigator +import com.wire.android.ui.destinations.AppUnlockWithBiometricsScreenDestination +import com.wire.android.ui.destinations.EnterLockCodeScreenDestination +import com.wire.android.ui.theme.WireTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class AppLockActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + WindowCompat.setDecorFitsSystemWindows(window, false) + setContent { + WireTheme { + val canAuthenticateWithBiometrics = BiometricManager + .from(this) + .canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) + + val navigator = rememberNavigator(this@AppLockActivity::finish) + + val startDestination = + if (canAuthenticateWithBiometrics == BiometricManager.BIOMETRIC_SUCCESS) { + appLogger.i("appLock: requesting app Unlock with biometrics") + AppUnlockWithBiometricsScreenDestination + } else { + appLogger.i("appLock: requesting app Unlock with passcode") + EnterLockCodeScreenDestination + } + + NavigationGraph( + navigator = navigator, + startDestination = startDestination + ) + } + } + } +} diff --git a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt index a87649f7ac..34df999ad8 100644 --- a/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt +++ b/app/src/main/kotlin/com/wire/android/ui/WireActivity.kt @@ -30,8 +30,6 @@ import androidx.activity.compose.setContent import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate -import androidx.biometric.BiometricManager -import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.SnackbarHostState @@ -71,9 +69,7 @@ import com.wire.android.ui.calling.ProximitySensorManager import com.wire.android.ui.common.snackbar.LocalSnackbarHostState import com.wire.android.ui.common.topappbar.CommonTopAppBar import com.wire.android.ui.common.topappbar.CommonTopAppBarViewModel -import com.wire.android.ui.destinations.AppUnlockWithBiometricsScreenDestination import com.wire.android.ui.destinations.ConversationScreenDestination -import com.wire.android.ui.destinations.EnterLockCodeScreenDestination import com.wire.android.ui.destinations.HomeScreenDestination import com.wire.android.ui.destinations.ImportMediaScreenDestination import com.wire.android.ui.destinations.IncomingCallScreenDestination @@ -100,7 +96,7 @@ import com.wire.android.util.ui.updateScreenSettings import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.onSubscription import kotlinx.coroutines.launch import javax.inject.Inject @@ -196,7 +192,6 @@ class WireActivity : AppCompatActivity() { setUpNavigation(navigator.navController, onComplete) isLoaded = true handleScreenshotCensoring() - handleAppLock(navigator::navigate) handleDialogs(navigator::navigate) } } @@ -250,28 +245,6 @@ class WireActivity : AppCompatActivity() { } } - @Composable - private fun handleAppLock(navigate: (NavigationCommand) -> Unit) { - LaunchedEffect(Unit) { - lifecycleScope.launch { - // Listen to one flow in a lifecycle-aware manner using flowWithLifecycle - lockCodeTimeManager.isLocked() - .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) - .filter { it } - .collectLatest { - val canAuthenticateWithBiometrics = BiometricManager - .from(this@WireActivity) - .canAuthenticate(BIOMETRIC_STRONG) - if (canAuthenticateWithBiometrics == BiometricManager.BIOMETRIC_SUCCESS) { - navigate(NavigationCommand(AppUnlockWithBiometricsScreenDestination, BackStackMode.UPDATE_EXISTED)) - } else { - navigate(NavigationCommand(EnterLockCodeScreenDestination, BackStackMode.UPDATE_EXISTED)) - } - } - } - } - } - @Composable private fun handleDialogs(navigate: (NavigationCommand) -> Unit) { featureFlagNotificationViewModel.loadInitialSync() @@ -355,6 +328,20 @@ class WireActivity : AppCompatActivity() { override fun onResume() { super.onResume() + + lifecycleScope.launch { + lockCodeTimeManager.observeAppLock() + // Listen to one flow in a lifecycle-aware manner using flowWithLifecycle + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .first().let { + if (it) { + startActivity( + Intent(this@WireActivity, AppLockActivity::class.java) + ) + } + } + } + proximitySensorManager.registerListener() } diff --git a/app/src/main/kotlin/com/wire/android/ui/common/scaffold/WireScaffold.kt b/app/src/main/kotlin/com/wire/android/ui/common/scaffold/WireScaffold.kt index 5577006d11..51726c348c 100644 --- a/app/src/main/kotlin/com/wire/android/ui/common/scaffold/WireScaffold.kt +++ b/app/src/main/kotlin/com/wire/android/ui/common/scaffold/WireScaffold.kt @@ -54,6 +54,7 @@ import com.wire.android.ui.common.snackbar.LocalSnackbarHostState @Composable fun WireScaffold( modifier: Modifier = Modifier, + snackbarHost: @Composable () -> Unit = { WireScaffoldSnackbarHost() }, topBar: @Composable () -> Unit = {}, bottomBar: @Composable () -> Unit = {}, floatingActionButton: @Composable () -> Unit = {}, @@ -68,18 +69,7 @@ fun WireScaffold( .systemBarsPadding(), topBar = topBar, bottomBar = bottomBar, - snackbarHost = { - SnackbarHost( - hostState = LocalSnackbarHostState.current, - snackbar = { data -> - SwipeableSnackbar( - hostState = LocalSnackbarHostState.current, - data = data, - onDismiss = { data.dismiss() } - ) - } - ) - }, + snackbarHost = snackbarHost, floatingActionButton = floatingActionButton, floatingActionButtonPosition = floatingActionButtonPosition, containerColor = containerColor, @@ -88,3 +78,17 @@ fun WireScaffold( content = content ) } + +@Composable +private fun WireScaffoldSnackbarHost() { + SnackbarHost( + hostState = LocalSnackbarHostState.current, + snackbar = { data -> + SwipeableSnackbar( + hostState = LocalSnackbarHostState.current, + data = data, + onDismiss = { data.dismiss() } + ) + } + ) +} diff --git a/app/src/main/kotlin/com/wire/android/ui/home/appLock/AppUnlockWithBiometricsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/appLock/AppUnlockWithBiometricsScreen.kt index 6e598841d9..b17f05c2d8 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/appLock/AppUnlockWithBiometricsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/appLock/AppUnlockWithBiometricsScreen.kt @@ -17,7 +17,7 @@ */ package com.wire.android.ui.home.appLock -import androidx.activity.compose.BackHandler +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -37,6 +37,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph import com.wire.android.R +import com.wire.android.appLogger import com.wire.android.biomitric.showBiometricPrompt import com.wire.android.navigation.BackStackMode import com.wire.android.navigation.NavigationCommand @@ -50,8 +51,50 @@ import com.wire.android.ui.destinations.EnterLockCodeScreenDestination @Composable fun AppUnlockWithBiometricsScreen( appUnlockWithBiometricsViewModel: AppUnlockWithBiometricsViewModel = hiltViewModel(), - navigator: Navigator, + navigator: Navigator ) { + AppUnLockBackground() + + val context = LocalContext.current + val tooManyAttemptsMessage = stringResource( + id = R.string.biometrics_app_unlock_too_many_attempts + ) + + LaunchedEffect(Unit) { + (context as AppCompatActivity).showBiometricPrompt( + onSuccess = { + appLogger.i("appLock: app Unlocked with biometrics") + appUnlockWithBiometricsViewModel.onAppUnlocked() + navigator.navigateBack() + }, + onCancel = { + appLogger.i("appLock: biometrics unlock canceled") + context.finishAffinity() + }, + onTooManyFailedAttempts = { + Toast.makeText(context, tooManyAttemptsMessage, Toast.LENGTH_SHORT).show() + navigator.navigate( + NavigationCommand( + destination = EnterLockCodeScreenDestination, + backStackMode = BackStackMode.REMOVE_CURRENT + ) + ) + }, + onRequestPasscode = { + appLogger.i("appLock: requesting passcode from biometrics unlock") + navigator.navigate( + NavigationCommand( + destination = EnterLockCodeScreenDestination, + backStackMode = BackStackMode.NONE + ) + ) + } + ) + } +} + +@Composable +private fun AppUnLockBackground() { Box( modifier = Modifier .fillMaxSize() @@ -65,29 +108,5 @@ fun AppUnlockWithBiometricsScreen( tint = MaterialTheme.colorScheme.onBackground, contentDescription = stringResource(id = R.string.content_description_welcome_wire_logo) ) - - val activity = LocalContext.current - LaunchedEffect(Unit) { - (activity as AppCompatActivity).showBiometricPrompt( - onSuccess = { - appUnlockWithBiometricsViewModel.onAppUnlocked() - navigator.navigateBack() - }, - onCancel = { - navigator.finish() - }, - onRequestPasscode = { - navigator.navigate( - NavigationCommand( - EnterLockCodeScreenDestination(), - BackStackMode.REMOVE_CURRENT - ) - ) - } - ) - } - } - BackHandler { - navigator.finish() } } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/appLock/EnterLockCodeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/appLock/EnterLockCodeScreen.kt index 0307c960c4..1f0c433831 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/appLock/EnterLockCodeScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/appLock/EnterLockCodeScreen.kt @@ -18,6 +18,7 @@ package com.wire.android.ui.home.appLock import androidx.activity.compose.BackHandler +import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.ScrollState import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box @@ -39,6 +40,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource @@ -49,6 +51,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.hilt.navigation.compose.hiltViewModel import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph +import com.ramcosta.composedestinations.utils.destination import com.wire.android.R import com.wire.android.navigation.Navigator import com.wire.android.navigation.rememberNavigator @@ -58,6 +61,7 @@ import com.wire.android.ui.common.rememberBottomBarElevationState import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.textfield.WirePasswordTextField import com.wire.android.ui.common.textfield.WireTextFieldState +import com.wire.android.ui.destinations.AppUnlockWithBiometricsScreenDestination import com.wire.android.ui.theme.WireTheme import com.wire.android.ui.theme.wireColorScheme import com.wire.android.ui.theme.wireDimensions @@ -77,8 +81,7 @@ fun EnterLockCodeScreen( state = viewModel.state, scrollState = rememberScrollState(), onPasswordChanged = viewModel::onPasswordChanged, - onContinue = viewModel::onContinue, - onBackPress = { navigator.finish() } + onContinue = viewModel::onContinue ) } @@ -89,19 +92,26 @@ fun EnterLockCodeScreenContent( state: EnterLockCodeViewState, scrollState: ScrollState, onPasswordChanged: (TextFieldValue) -> Unit, - onBackPress: () -> Unit, onContinue: () -> Unit ) { + val context = LocalContext.current LaunchedEffect(state.done) { if (state.done) { navigator.navigateBack() } } + BackHandler { - onBackPress() + if (navigator.navController.previousBackStackEntry?.destination() is AppUnlockWithBiometricsScreenDestination) { + navigator.navigateBack() + } else { + (context as AppCompatActivity).finishAffinity() + } } - WireScaffold { internalPadding -> + WireScaffold( + snackbarHost = {} + ) { internalPadding -> Column( modifier = Modifier .fillMaxSize() @@ -145,11 +155,14 @@ fun EnterLockCodeScreenContent( EnterLockCodeError.InvalidValue -> WireTextFieldState.Error( errorText = stringResource(R.string.settings_enter_lock_screen_wrong_passcode_label) ) + EnterLockCodeError.None -> WireTextFieldState.Default }, autofill = false, placeholderText = stringResource(R.string.settings_set_lock_screen_passcode_label), - labelText = stringResource(R.string.settings_set_lock_screen_passcode_label).uppercase(Locale.getDefault()) + labelText = stringResource(R.string.settings_set_lock_screen_passcode_label).uppercase( + Locale.getDefault() + ) ) Spacer(modifier = Modifier.weight(1f)) } @@ -202,7 +215,6 @@ fun PreviewEnterLockCodeScreen() { state = EnterLockCodeViewState(), scrollState = rememberScrollState(), onPasswordChanged = {}, - onBackPress = {}, onContinue = {} ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManager.kt b/app/src/main/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManager.kt index bd2ef0e668..2a0d6bc905 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManager.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManager.kt @@ -94,7 +94,9 @@ class LockCodeTimeManager @Inject constructor( isLockedFlow.value = false } - fun isLocked(): Flow = isLockedFlow + fun isAppLocked(): Boolean = isLockedFlow.value + + fun observeAppLock(): Flow = isLockedFlow companion object { private const val TAG = "LockCodeTimeManager" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b169ea5b30..27984a471e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1266,6 +1266,7 @@ Authenticate with biometrics To unlock Wire Use passcode + Too many attempts on Biometrics. Unlock with passcode instead. Certificate Details Copy to Clipboard diff --git a/app/src/test/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManagerTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManagerTest.kt index b907789886..716627ec28 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManagerTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/appLock/LockCodeTimeManagerTest.kt @@ -52,7 +52,7 @@ class LockCodeTimeManagerTest { arrangement.withIsAppVisible(true) advanceUntilIdle() // then - assertEquals(expected, manager.isLocked().first()) + assertEquals(expected, manager.observeAppLock().first()) } @Test @@ -75,7 +75,7 @@ class LockCodeTimeManagerTest { arrangement.withIsAppVisible(false) advanceTimeBy(delayAfterStop) // then - assertEquals(expected, manager.isLocked().first()) + assertEquals(expected, manager.observeAppLock().first()) } @Test @@ -104,7 +104,7 @@ class LockCodeTimeManagerTest { manager.appUnlocked() advanceUntilIdle() // when-then - manager.isLocked().test { + manager.observeAppLock().test { arrangement.withIsAppVisible(false) assertEquals(false, awaitItem()) assertEquals(true, awaitItem()) @@ -124,7 +124,7 @@ class LockCodeTimeManagerTest { advanceTimeBy(startDelay) arrangement.withIsAppVisible(true) // then - assertEquals(expected, manager.isLocked().first()) + assertEquals(expected, manager.observeAppLock().first()) } @Test @@ -155,7 +155,7 @@ class LockCodeTimeManagerTest { advanceTimeBy(AppLockConfig.Enabled.timeoutInMillis() - 100L) arrangement.withIsAppVisible(true) // then - assertEquals(true, manager.isLocked().first()) + assertEquals(true, manager.observeAppLock().first()) } @Test @@ -170,7 +170,7 @@ class LockCodeTimeManagerTest { manager.appUnlocked() advanceUntilIdle() // then - assertEquals(false, manager.isLocked().first()) + assertEquals(false, manager.observeAppLock().first()) } class Arrangement(dispatcher: TestDispatcher) { diff --git a/kalium b/kalium index 07301bd8a1..033a8ffbc4 160000 --- a/kalium +++ b/kalium @@ -1 +1 @@ -Subproject commit 07301bd8a120b930e057a94c1d80fb99e9edc16f +Subproject commit 033a8ffbc4a23baae24cd708eb5faa22c0da303d