NTP-66799 | Android App lock - Biometric (#16437)

This commit is contained in:
Aparna Vadlamani
2025-06-05 14:40:38 +05:30
committed by GitHub
parent 4b3b148eaf
commit 1a63d9cdb2
9 changed files with 142 additions and 146 deletions

View File

@@ -8,14 +8,11 @@
package com.naviapp.app.initializers
import android.app.Activity
import android.os.Build
import android.os.Bundle
import android.view.WindowManager
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.base.sharedpref.PreferenceManager
import com.navi.base.utils.AppLaunchUtils
import com.navi.base.utils.coroutine.CoroutineManager
import com.navi.base.utils.isNull
import com.navi.chat.base.ChatBaseActivity
import com.navi.common.NaviActivityLifecycleCallbacks
import com.navi.common.checkmate.core.CheckMateManager
@@ -28,8 +25,6 @@ import com.navi.common.resourcemanager.manager.ResourceManager
import com.navi.common.ui.activity.BaseActivity
import com.navi.common.utils.BiometricPromptUtils
import com.navi.common.utils.CommonUtils.isQaRelease
import com.navi.common.utils.Constants.ScreenLockConstants.ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.IS_SCREEN_LOCK_ENABLED
import com.navi.insurance.health.activity.BaseActivity as InsuranceBaseActivity
import com.navi.pay.common.setup.NaviPayManager
import com.naviapp.analytics.utils.NaviAnalytics.Companion.EXTERNAL
@@ -66,16 +61,6 @@ constructor(
if (activity is HomePageActivity) {
AppLaunchUtils.resetAppOpenOnLaunch()
}
CoroutineScope(Dispatchers.IO).launch {
if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED)
.isNull() &&
BiometricPromptUtils().isDeviceSecure(application)
) {
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, ENABLED)
}
}
}
override fun onActivityStarted(activity: Activity) {
@@ -163,7 +148,6 @@ constructor(
application.decrementAppInForeground()
if (application.getAppInForegroundCounter() == 0) {
BiometricPromptUtils.appInBackgroundTimeStamp = System.currentTimeMillis()
startSessionDetails?.let { initSessionDetails ->
CoroutineScope(Dispatchers.IO).launch {
val endSessionDetails = getCurrentSessionMetrics(application)
@@ -200,6 +184,7 @@ constructor(
eventName = NAVIAPP_BACKGROUND_PUSH,
mapOf("screenName" to screenName),
)
BiometricPromptUtils.appInBackgroundTimeStamp = System.currentTimeMillis()
}
}
}

View File

@@ -64,6 +64,7 @@ import com.navi.common.model.common.NetworkConnectivityNudgeData
import com.navi.common.network.models.GenericErrorResponse
import com.navi.common.resourcemanager.manager.ResourceManager
import com.navi.common.utils.ApiPollScheduler
import com.navi.common.utils.BiometricPromptUtils
import com.navi.common.utils.BiometricPromptUtils.Companion.getScreenLockEventName
import com.navi.common.utils.CommonNaviAnalytics
import com.navi.common.utils.Constants.IN_APP_UPDATE_REQUEST_CODE
@@ -71,7 +72,6 @@ import com.navi.common.utils.Constants.NAVI_PAY_SECTION_GLANCE_WIDGET_SCREEN
import com.navi.common.utils.Constants.SUB_REDIRECT
import com.navi.common.utils.Constants.ScreenLockConstants.DISABLED
import com.navi.common.utils.Constants.ScreenLockConstants.ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.HPC_SCREEN_LOCK_EXPERIMENT
import com.navi.common.utils.Constants.ScreenLockConstants.IS_SCREEN_LOCK_ENABLED
import com.navi.common.utils.TemporaryStorageHelper
import com.navi.common.utils.getDeviceSignature
@@ -535,9 +535,10 @@ class HomePageActivity :
observeGIPaymentFailed()
observeNetworkConnectivity()
observeLoansTabPaymentData()
observeScreenLockEnabledData()
observeScreenLockToggleData()
observeCollectRequestFromPn()
observeScreenOverlayEffect()
observeScreenLockEnableStatus()
}
private fun observeScreenOverlayEffect() {
@@ -588,6 +589,28 @@ class HomePageActivity :
}
}
private fun observeScreenLockEnableStatus() {
lifecycleScope.launch(Dispatchers.IO) {
homeVM.handle.getStateFlow<String?>(IS_SCREEN_LOCK_ENABLED, null).collect { state ->
when (state) {
ENABLED -> {
if (
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) == null &&
biometricPromptUtils.isDeviceSecure(this@HomePageActivity)
) {
BiometricPromptUtils().reset()
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, ENABLED)
}
}
DISABLED -> {
BiometricPromptUtils().reset()
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, DISABLED)
}
}
}
}
}
private fun observeCollectRequestFromPn() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -603,17 +626,20 @@ class HomePageActivity :
}
}
private fun observeScreenLockEnabledData() {
private fun observeScreenLockToggleData() {
lifecycleScope.launch(Dispatchers.IO) {
repeatOnLifecycle(state = Lifecycle.State.STARTED) {
profileVM.isScreenLockToggled.collect { isScreenLockToggled ->
profileVM.handle.getStateFlow<String?>(IS_SCREEN_LOCK_ENABLED, null).collect {
isScreenLockToggled ->
NaviTrackEvent.trackEventOnClickStream(
eventName =
getScreenLockEventName(eventType = ::observeScreenLockEnabledData.name)
getScreenLockEventName(eventType = ::observeScreenLockToggleData.name)
)
isScreenLockToggled?.let {
profileVM.canCachedDataBeUsed = false
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, it)
if (PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) != it)
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, it)
else return@collect
biometricPromptUtils.reset()
}
if (
@@ -907,13 +933,11 @@ class HomePageActivity :
if (fetchDataDisabled.not()) {
profileVM.fetchProfileItems(
isScreenLockEnabled =
FirebaseRemoteConfigHelper.getBoolean(IS_SCREEN_LOCK_ENABLED) &&
PreferenceManager.getStringPreference(HPC_SCREEN_LOCK_EXPERIMENT) ==
ENABLED,
FirebaseRemoteConfigHelper.getBoolean(IS_SCREEN_LOCK_ENABLED),
isMobileScreenLockSet =
biometricPromptUtils.isDeviceSecure(this@HomePageActivity) &&
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) !=
DISABLED,
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) ==
ENABLED,
naeScreenName = screenName,
isProfileDrawerOpen = isProfileDrawerOpen,
)

View File

@@ -21,7 +21,6 @@ import com.navi.common.network.models.RepoResult
import com.navi.common.utils.BiometricPromptUtils
import com.navi.common.utils.Constants.ScreenLockConstants.DISABLED
import com.navi.common.utils.Constants.ScreenLockConstants.ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.HPC_SCREEN_LOCK_EXPERIMENT
import com.navi.common.utils.Constants.ScreenLockConstants.IS_SCREEN_LOCK_ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.TOGGLE_SWITCH_CHECKED_STATE
import com.navi.common.utils.Constants.ScreenLockConstants.TOGGLE_SWITCH_LAYOUT_ID
@@ -44,9 +43,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.update
@@ -67,9 +64,6 @@ constructor(
MutableStateFlow<ProfileScreenState>(ProfileScreenState.Loading)
val profileScreenDataState = _profileScreenDataState.asStateFlow()
private val _isScreenLockToggled = MutableSharedFlow<String?>()
val isScreenLockToggled = _isScreenLockToggled.asSharedFlow()
private lateinit var cacheResponse: ScreenDefinition
var canCachedDataBeUsed: Boolean = true
@@ -93,13 +87,11 @@ constructor(
} else {
getProfileResponseFromApi(
isScreenLockEnabled =
FirebaseRemoteConfigHelper.getBoolean(IS_SCREEN_LOCK_ENABLED) &&
PreferenceManager.getStringPreference(HPC_SCREEN_LOCK_EXPERIMENT) ==
ENABLED,
FirebaseRemoteConfigHelper.getBoolean(IS_SCREEN_LOCK_ENABLED),
isMobileScreenLockSet =
biometricPromptUtils.isDeviceSecure(context) &&
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) !=
DISABLED,
PreferenceManager.getStringPreference(IS_SCREEN_LOCK_ENABLED) ==
ENABLED,
naeScreenName = NaviAnalytics.NEW_HOME_ACTIVITY,
isNaeRequired = false,
)
@@ -108,7 +100,6 @@ constructor(
}
private fun initListeners() {
observeScreenToggleDataFromHandle()
observeBiometricAuthenticationEnabledStatus()
observeEmailSuccess()
}
@@ -128,14 +119,6 @@ constructor(
}
}
private fun observeScreenToggleDataFromHandle() {
viewModelScope.launch(Dispatchers.IO) {
handle.getStateFlow<String?>(IS_SCREEN_LOCK_ENABLED, null).collect { state ->
_isScreenLockToggled.emit(state)
}
}
}
private fun observeBiometricAuthenticationEnabledStatus() {
viewModelScope.launch(Dispatchers.IO) {
BiometricPromptUtils.isBiometricAuthenticationEnabled.collect { state ->
@@ -162,6 +145,7 @@ constructor(
}
fun enabledToggle() {
PreferenceManager.setStringPreference(IS_SCREEN_LOCK_ENABLED, ENABLED)
handle[IS_SCREEN_LOCK_ENABLED] = ENABLED
handleActions(
UiTronActionData(

View File

@@ -12,15 +12,12 @@ import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import com.navi.analytics.utils.NaviTrackEvent
import com.navi.analytics.utils.NaviTrackEvent.trackEventOnClickStream
import com.navi.base.sharedpref.PreferenceManager
import com.navi.base.utils.BaseUtils
import com.navi.base.utils.isNull
import com.navi.base.utils.orTrue
import com.navi.common.constants.APP_UPGRADE_DATA
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.model.AppUpgradeResponse
import com.navi.common.ui.activity.BaseActivity
import com.navi.common.utils.Constants.ScreenLockConstants.HPC_SCREEN_LOCK_EXPERIMENT
import com.navi.common.utils.observeNonNull
import com.navi.common.utils.observeNullable
import com.navi.insurance.util.Constants.CLICKED
@@ -72,7 +69,6 @@ abstract class BaseLauncherActivity : BaseActivity() {
uploadAnalyticsData()
updateFcmToken()
updateMarketingDataToSaphyra()
fetchScreenLockExperiment()
}
fun initJuspaySDK() {
@@ -103,15 +99,6 @@ abstract class BaseLauncherActivity : BaseActivity() {
launcherVM.fetchLoginSettings(naeScreenName = screenName)
}
private fun fetchScreenLockExperiment() {
if (
BaseUtils.isUserLoggedIn() &&
PreferenceManager.getStringPreference(HPC_SCREEN_LOCK_EXPERIMENT).isNull()
) {
launcherVM.fetchABExperiment(HPC_SCREEN_LOCK_EXPERIMENT)
}
}
private fun setFirebaseAppInstanceId() {
launcherVM.setFirebaseAppInstanceId()
}

View File

@@ -24,15 +24,11 @@ import com.navi.base.sharedpref.CommonPrefConstants.PREVIOUS_APPSFLYER_ID
import com.navi.base.sharedpref.CommonPrefConstants.PREVIOUS_GOOGLE_ADVERTISEMENT_ID
import com.navi.base.sharedpref.PreferenceManager
import com.navi.base.utils.BaseUtils
import com.navi.base.utils.isNotNull
import com.navi.base.utils.orFalse
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.managers.NaviLocationManager
import com.navi.common.model.CommunicationAppLaunchData
import com.navi.common.utils.Constants.SAPHYRA_APP_LOGIN_EVENT
import com.navi.common.utils.Constants.ScreenLockConstants.DISABLED
import com.navi.common.utils.Constants.ScreenLockConstants.ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.HPC_SCREEN_LOCK_EXPERIMENT
import com.navi.common.utils.deviceId
import com.navi.common.utils.getAppsflyerUid
import com.navi.common.utils.isValidResponse
@@ -250,23 +246,4 @@ constructor(
}
}
}
fun fetchABExperiment(experimentName: String) {
viewModelScope.launch(Dispatchers.IO) {
val response = configRepository.fetchABExperiment(experimentName)
if (response.isSuccessful && response.body()?.result.isNotNull()) {
val experimentResult =
response.body()?.result?.let {
when (it) {
true -> ENABLED
false -> DISABLED
}
}
experimentResult?.let { result ->
PreferenceManager.setStringPreference(HPC_SCREEN_LOCK_EXPERIMENT, result)
}
}
}
}
}

View File

@@ -9,6 +9,7 @@ package com.navi.common.ui.dialog
import android.os.Bundle
import android.view.ViewStub
import android.view.WindowManager
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -16,12 +17,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -36,6 +39,8 @@ import androidx.databinding.DataBindingUtil
import com.navi.common.R
import com.navi.common.databinding.NaviLockScreenDialogBinding
import com.navi.common.ui.fragment.BaseBottomSheet
import com.navi.common.utils.BiometricAuthenticationStatus
import com.navi.common.utils.BiometricPromptUtils
import com.navi.design.font.FontWeightEnum
import com.navi.design.font.getFontWeight
import com.navi.design.font.naviFontFamily
@@ -60,12 +65,6 @@ class NaviLockScreenDialog : BaseBottomSheet() {
}
override fun setContainerView(viewStub: ViewStub) {
setBackgroundTint(
ContextCompat.getColor(
requireContext(),
com.navi.design.R.color.translucent_blue_midnight,
)
)
viewStub.layoutResource = R.layout.navi_lock_screen_dialog
binding = DataBindingUtil.getBinding(viewStub.inflate())!!
initUI()
@@ -77,62 +76,89 @@ class NaviLockScreenDialog : BaseBottomSheet() {
@Composable
fun LockScreen() {
Box(modifier = Modifier.fillMaxWidth().wrapContentSize()) {
Column(
modifier =
Modifier.fillMaxWidth()
.align(Alignment.BottomCenter)
.background(
color = Color.White,
shape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp),
)
.padding(all = 16.dp)
) {
Image(
painter = painterResource(id = R.drawable.ic_purple_lock),
contentDescription = null,
val showDialog =
remember(BiometricPromptUtils.biometricAuthenticationStatus.value) {
mutableStateOf(
BiometricPromptUtils.biometricAuthenticationStatus.value ==
BiometricAuthenticationStatus.FAILED
)
Text(
modifier = Modifier.padding(top = 8.dp),
text = resources.getString(R.string.navi_app_is_locked),
style = TextStyle(fontFamily = naviFontFamily),
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
fontSize = 16.sp,
color = FF191919,
textAlign = TextAlign.Start,
}
if (showDialog.value) {
requireActivity().window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
setBackgroundTint(
ContextCompat.getColor(
requireContext(),
com.navi.design.R.color.translucent_blue_midnight,
)
Text(
modifier = Modifier.padding(top = 8.dp),
text = resources.getString(R.string.your_sensitive_data_is_protected),
style = TextStyle(fontFamily = naviFontFamily),
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
fontSize = 14.sp,
color = FF6B6B6B,
textAlign = TextAlign.Start,
)
Row(
)
Box(modifier = Modifier.fillMaxSize()) {
Column(
modifier =
Modifier.fillMaxWidth()
.padding(top = 32.dp, bottom = 16.dp)
.align(Alignment.BottomCenter)
.background(
color = Color(0xFF1F002A),
shape = RoundedCornerShape(size = 4.dp),
color = Color.White,
shape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp),
)
.padding(all = 16.dp)
.clickable { unlock?.invoke() },
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = painterResource(id = R.drawable.ic_purple_lock),
contentDescription = null,
)
Text(
text = resources.getString(R.string.log_in_securely),
modifier = Modifier.padding(top = 8.dp),
text = resources.getString(R.string.navi_app_is_locked),
style = TextStyle(fontFamily = naviFontFamily),
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
fontSize = 14.sp,
color = Color.White,
textAlign = TextAlign.Center,
fontSize = 16.sp,
color = FF191919,
textAlign = TextAlign.Start,
)
Text(
modifier = Modifier.padding(top = 8.dp),
text = resources.getString(R.string.your_sensitive_data_is_protected),
style = TextStyle(fontFamily = naviFontFamily),
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
fontSize = 14.sp,
color = FF6B6B6B,
textAlign = TextAlign.Start,
)
Row(
modifier =
Modifier.fillMaxWidth()
.padding(top = 32.dp, bottom = 16.dp)
.background(
color = Color(0xFF1F002A),
shape = RoundedCornerShape(size = 4.dp),
)
.padding(all = 16.dp)
.clickable { unlock?.invoke() },
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = resources.getString(R.string.log_in_securely),
style = TextStyle(fontFamily = naviFontFamily),
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
fontSize = 14.sp,
color = Color.White,
textAlign = TextAlign.Center,
)
}
}
}
} else {
setBackgroundTint(
ContextCompat.getColor(requireContext(), com.navi.design.R.color.black_opacity_0)
)
Box(
modifier =
Modifier.fillMaxSize().background(color = Color.Transparent).clickable(
enabled = false
) {}
)
}
}

View File

@@ -11,12 +11,15 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.view.WindowManager
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.BiometricPrompt
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.navi.analytics.utils.NaviTrackEvent
@@ -28,7 +31,6 @@ import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.utils.Constants.ScreenLockConstants.AUTHENTICATION_SESSION_TIME_OUT_THRESHOLD
import com.navi.common.utils.Constants.ScreenLockConstants.DISABLED
import com.navi.common.utils.Constants.ScreenLockConstants.ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.HPC_SCREEN_LOCK_EXPERIMENT
import com.navi.common.utils.Constants.ScreenLockConstants.IS_SCREEN_LOCK_ENABLED
import com.navi.common.utils.Constants.ScreenLockConstants.LOGIN_SESSION_ID
import kotlinx.coroutines.Dispatchers
@@ -55,7 +57,6 @@ class BiometricPromptUtils {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
FirebaseRemoteConfigHelper.getBoolean(IS_SCREEN_LOCK_ENABLED) &&
BaseUtils.isUserLoggedIn() &&
PreferenceManager.getStringPreference(HPC_SCREEN_LOCK_EXPERIMENT) == ENABLED &&
isScreenLockToggled == ENABLED
}
@@ -78,7 +79,7 @@ class BiometricPromptUtils {
NaviTrackEvent.trackEventOnClickStream(
eventName = getScreenLockEventName(eventType = ::onAuthenticationError.name)
)
biometricAuthenticationStatus = BiometricAuthenticationStatus.FAILED
biometricAuthenticationStatus.value = BiometricAuthenticationStatus.FAILED
onFailed()
}
@@ -88,7 +89,7 @@ class BiometricPromptUtils {
eventName =
getScreenLockEventName(eventType = ::onAuthenticationFailed.name)
)
biometricAuthenticationStatus = BiometricAuthenticationStatus.FAILED
biometricAuthenticationStatus.value = BiometricAuthenticationStatus.FAILED
onFailed()
}
@@ -101,8 +102,9 @@ class BiometricPromptUtils {
getScreenLockEventName(eventType = ::onAuthenticationSucceeded.name)
)
reset()
biometricAuthenticationStatus = BiometricAuthenticationStatus.SUCCESS
biometricAuthenticationStatus.value = BiometricAuthenticationStatus.SUCCESS
onSuccess()
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
}
}
return BiometricPrompt(activity, executor, callback)
@@ -164,11 +166,10 @@ class BiometricPromptUtils {
) && PreferenceManager.getStringPreference(LOGIN_SESSION_ID) != getSessionId()
) {
if (isDeviceSecure(activity)) {
if (
isAuthenticationSessionExpired() ||
biometricAuthenticationStatus == BiometricAuthenticationStatus.FAILED
) {
if (isAuthenticationSessionExpired() || hasBiometricAuthenticationFailed()) {
withContext(Dispatchers.Main) {
activity.window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
showLockScreenDialog()
showBiometricPrompt(
activity = activity,
onSuccess = hideLockScreenDialog,
@@ -193,10 +194,15 @@ class BiometricPromptUtils {
return result
}
private fun hasBiometricAuthenticationFailed(): Boolean {
return biometricAuthenticationStatus.value != BiometricAuthenticationStatus.SUCCESS &&
biometricAuthenticationStatus.value != BiometricAuthenticationStatus.RESET
}
fun reset() {
appInForegroundTimeStamp = null
appInBackgroundTimeStamp = null
biometricAuthenticationStatus = null
biometricAuthenticationStatus.value = BiometricAuthenticationStatus.RESET
}
companion object {
@@ -204,16 +210,19 @@ class BiometricPromptUtils {
var appInBackgroundTimeStamp: Long? = null
private var biometricAuthenticationStatus: BiometricAuthenticationStatus? = null
var biometricAuthenticationStatus: MutableState<BiometricAuthenticationStatus?> =
mutableStateOf(null)
private set
private val _isBiometricAuthenticationEnabled = MutableSharedFlow<String?>()
val isBiometricAuthenticationEnabled = _isBiometricAuthenticationEnabled.asSharedFlow()
fun getScreenLockEventName(eventType: String) = "screen_lock_${eventType}"
fun getScreenLockEventName(eventType: String) = "naviapp_screen_lock_${eventType}"
}
}
enum class BiometricAuthenticationStatus {
SUCCESS,
FAILED,
RESET,
}

View File

@@ -375,7 +375,6 @@ object Constants {
const val ENABLED = "ENABLED"
const val DISABLED = "DISABLED"
const val IS_SCREEN_LOCK_ENABLED = "IS_SCREEN_LOCK_ENABLED"
const val HPC_SCREEN_LOCK_EXPERIMENT = "hpc-screen-lock-experiment"
const val TOGGLE_SWITCH_LAYOUT_ID = "lock_screen_toggle_switch"
const val TOGGLE_SWITCH_UNCHECKED_STATE = "unchecked"
const val TOGGLE_SWITCH_CHECKED_STATE = "checked"

View File

@@ -113,7 +113,12 @@
<style name="FullScreenDialogFragmentWithPurpleBackground" parent="AppTheme.NoActionBar.FullScreen">
<item name="android:windowFullscreen">true</item>
<item name="android:windowAnimationStyle">@style/Animation.Design.BottomSheetDialog</item>
<item name="android:windowBackground">@color/translucent_blue_midnight</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="FullScreenDialogFragmentWithNoAnimation" parent="AppTheme.NoActionBar.FullScreen">