1
1
package com.bintianqi.owndroid
2
2
3
3
import android.content.Context
4
+ import androidx.activity.compose.BackHandler
4
5
import androidx.biometric.BiometricManager
5
6
import androidx.biometric.BiometricPrompt
6
7
import androidx.biometric.BiometricPrompt.AuthenticationCallback
7
8
import androidx.biometric.BiometricPrompt.PromptInfo.Builder
8
- import androidx.compose.animation.core.animateFloatAsState
9
- import androidx.compose.foundation.background
10
- import androidx.compose.foundation.isSystemInDarkTheme
11
9
import androidx.compose.foundation.layout.Arrangement
12
10
import androidx.compose.foundation.layout.Column
13
11
import androidx.compose.foundation.layout.fillMaxSize
12
+ import androidx.compose.foundation.layout.padding
14
13
import androidx.compose.material3.Button
15
14
import androidx.compose.material3.MaterialTheme
16
- import androidx.compose.material3.Surface
15
+ import androidx.compose.material3.Scaffold
17
16
import androidx.compose.material3.Text
18
17
import androidx.compose.runtime.*
18
+ import androidx.compose.runtime.saveable.rememberSaveable
19
19
import androidx.compose.ui.Alignment
20
20
import androidx.compose.ui.Modifier
21
- import androidx.compose.ui.draw.alpha
22
- import androidx.compose.ui.graphics.Color
23
21
import androidx.compose.ui.res.stringResource
24
22
import androidx.core.content.ContextCompat
25
23
import androidx.fragment.app.FragmentActivity
26
- import com.bintianqi.owndroid.ui.Animations
24
+ import androidx.navigation.NavHostController
27
25
import kotlinx.coroutines.delay
28
- import kotlinx.coroutines.launch
29
26
30
27
@Composable
31
- fun AuthScreen (activity : FragmentActivity , showAuth : MutableState <Boolean >) {
32
- val context = activity.applicationContext
33
- val coroutineScope = rememberCoroutineScope()
34
- var canStartAuth by remember { mutableStateOf(true ) }
35
- var fallback by remember { mutableStateOf(false ) }
36
- var startFade by remember { mutableStateOf(false ) }
37
- val alpha by animateFloatAsState(
38
- targetValue = if (startFade) 0F else 1F ,
39
- label = " AuthScreenFade" ,
40
- animationSpec = Animations .authScreenFade
41
- )
42
- val onAuthSucceed = {
43
- startFade = true
44
- coroutineScope.launch {
45
- delay(300 )
46
- showAuth.value = false
47
- }
48
- }
49
- val promptInfo = Builder ()
50
- .setTitle(context.getText(R .string.authenticate))
51
- .setSubtitle(context.getText(R .string.auth_with_bio))
52
- .setConfirmationRequired(true )
28
+ fun Authenticate (activity : FragmentActivity , navCtrl : NavHostController ) {
29
+ BackHandler { activity.moveTaskToBack(true ) }
30
+ var status by rememberSaveable { mutableIntStateOf(0 ) } // 0:Prompt automatically, 1:Authenticating, 2:Prompt manually
31
+ val onAuthSucceed = { navCtrl.navigateUp() }
53
32
val callback = object : AuthenticationCallback () {
54
33
override fun onAuthenticationSucceeded (result : BiometricPrompt .AuthenticationResult ) {
55
34
super .onAuthenticationSucceeded(result)
@@ -59,81 +38,49 @@ fun AuthScreen(activity: FragmentActivity, showAuth: MutableState<Boolean>) {
59
38
super .onAuthenticationError(errorCode, errString)
60
39
when (errorCode) {
61
40
BiometricPrompt .ERROR_NO_DEVICE_CREDENTIAL -> onAuthSucceed()
62
- BiometricPrompt .ERROR_NEGATIVE_BUTTON -> fallback = true
63
- else -> canStartAuth = true
41
+ else -> status = 2
64
42
}
65
43
}
66
44
}
67
- LaunchedEffect (fallback) {
68
- if (fallback) {
69
- val fallbackPromptInfo = promptInfo
70
- .setAllowedAuthenticators(BiometricManager .Authenticators .DEVICE_CREDENTIAL )
71
- .setSubtitle(context.getText(R .string.auth_with_password))
72
- .build()
73
- val executor = ContextCompat .getMainExecutor(context)
74
- val biometricPrompt = BiometricPrompt (activity, executor, callback)
75
- biometricPrompt.authenticate(fallbackPromptInfo)
45
+ LaunchedEffect (Unit ) {
46
+ if (status == 0 ) {
47
+ delay(300 )
48
+ startAuth(activity, callback)
49
+ status = 1
76
50
}
77
51
}
78
- Surface (
79
- modifier = Modifier
80
- .fillMaxSize()
81
- .alpha(alpha)
82
- .background(if (isSystemInDarkTheme()) Color .Black else Color .White )
83
- ) {
52
+ Scaffold { paddingValues ->
84
53
Column (
85
54
horizontalAlignment = Alignment .CenterHorizontally ,
86
55
verticalArrangement = Arrangement .Center ,
87
- modifier = Modifier .fillMaxSize().background( MaterialTheme .colorScheme.background )
56
+ modifier = Modifier .fillMaxSize().padding(paddingValues )
88
57
) {
89
- LaunchedEffect (Unit ) {
90
- delay(300 )
91
- startAuth(activity, promptInfo, callback)
92
- canStartAuth = false
93
- }
94
58
Text (
95
59
text = stringResource(R .string.authenticate),
96
60
style = MaterialTheme .typography.headlineLarge,
97
- color = MaterialTheme .colorScheme.onBackground
98
61
)
99
62
Button (
100
63
onClick = {
101
- startAuth(activity, promptInfo, callback)
102
- canStartAuth = false
64
+ startAuth(activity, callback)
65
+ status = 1
103
66
},
104
- enabled = canStartAuth
67
+ enabled = status != 1
105
68
) {
106
69
Text (text = stringResource(R .string.start))
107
70
}
108
71
}
109
72
}
110
73
}
111
74
112
- private fun startAuth (activity : FragmentActivity , basicPromptInfo : Builder , callback : AuthenticationCallback ) {
75
+ fun startAuth (activity : FragmentActivity , callback : AuthenticationCallback ) {
113
76
val context = activity.applicationContext
114
- val promptInfo = basicPromptInfo
115
- val bioManager = BiometricManager .from(context)
116
77
val sharedPref = context.getSharedPreferences(" data" , Context .MODE_PRIVATE )
117
- if (sharedPref.getBoolean(" bio_auth" , false )) {
118
- when (BiometricManager .BIOMETRIC_SUCCESS ) {
119
- bioManager.canAuthenticate(BiometricManager .Authenticators .BIOMETRIC_STRONG ) ->
120
- promptInfo
121
- .setAllowedAuthenticators(BiometricManager .Authenticators .BIOMETRIC_STRONG )
122
- .setNegativeButtonText(context.getText(R .string.use_password))
123
- bioManager.canAuthenticate(BiometricManager .Authenticators .BIOMETRIC_WEAK ) ->
124
- promptInfo
125
- .setAllowedAuthenticators(BiometricManager .Authenticators .BIOMETRIC_WEAK )
126
- .setNegativeButtonText(context.getText(R .string.use_password))
127
- else -> promptInfo
128
- .setAllowedAuthenticators(BiometricManager .Authenticators .DEVICE_CREDENTIAL )
129
- .setSubtitle(context.getText(R .string.auth_with_password))
130
- }
131
- }else {
132
- promptInfo
133
- .setAllowedAuthenticators(BiometricManager .Authenticators .DEVICE_CREDENTIAL )
134
- .setSubtitle(context.getText(R .string.auth_with_password))
78
+ val promptInfo = Builder ().setTitle(context.getText(R .string.authenticate))
79
+ if (sharedPref.getInt(" biometrics_auth" , 0 ) != 0 ) {
80
+ promptInfo.setAllowedAuthenticators(BiometricManager .Authenticators .DEVICE_CREDENTIAL or BiometricManager .Authenticators .BIOMETRIC_WEAK )
81
+ } else {
82
+ promptInfo.setAllowedAuthenticators(BiometricManager .Authenticators .DEVICE_CREDENTIAL )
135
83
}
136
84
val executor = ContextCompat .getMainExecutor(context)
137
- val biometricPrompt = BiometricPrompt (activity, executor, callback)
138
- biometricPrompt.authenticate(promptInfo.build())
85
+ BiometricPrompt (activity, executor, callback).authenticate(promptInfo.build())
139
86
}
0 commit comments