diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ade3fe8381a..bbb40da9683 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 923e7b58a36..aab9c2f55ce 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 01e30c3845f..d118304ad08 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 00000000000..50dbd4aa1ee
--- /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 a87649f7acc..34df999ad88 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 5577006d118..51726c348c0 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 6e598841d99..b17f05c2d8a 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 0307c960c4d..1f0c4338314 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 bd2ef0e668a..2a0d6bc9052 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 b169ea5b30b..27984a471e5 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 b9077898866..716627ec28f 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 07301bd8a12..033a8ffbc4a 160000
--- a/kalium
+++ b/kalium
@@ -1 +1 @@
-Subproject commit 07301bd8a120b930e057a94c1d80fb99e9edc16f
+Subproject commit 033a8ffbc4a23baae24cd708eb5faa22c0da303d