1717package org .thoughtcrime .securesms ;
1818
1919import android .animation .Animator ;
20- import android .annotation .SuppressLint ;
2120import android .app .KeyguardManager ;
2221import android .content .Context ;
2322import android .content .Intent ;
4645import android .widget .ImageView ;
4746import android .widget .TextView ;
4847
48+ import androidx .annotation .NonNull ;
4949import androidx .appcompat .widget .Toolbar ;
50- import androidx .core .hardware .fingerprint .FingerprintManagerCompat ;
51- import androidx .core .os .CancellationSignal ;
50+ import androidx .biometric .BiometricManager ;
51+ import androidx .biometric .BiometricManager .Authenticators ;
52+ import androidx .biometric .BiometricPrompt ;
5253
5354import org .signal .core .util .logging .Log ;
5455import org .thoughtcrime .securesms .animation .AnimationCompleteListener ;
7071 */
7172public class PassphrasePromptActivity extends PassphraseActivity {
7273
73- private static final String TAG = PassphrasePromptActivity .class .getSimpleName ();
74+ private static final String TAG = Log .tag (PassphrasePromptActivity .class );
75+ private static final int BIOMETRIC_AUTHENTICATORS = Authenticators .BIOMETRIC_STRONG | Authenticators .BIOMETRIC_WEAK ;
76+ private static final int ALLOWED_AUTHENTICATORS = BIOMETRIC_AUTHENTICATORS | Authenticators .DEVICE_CREDENTIAL ;
77+ private static final short AUTHENTICATE_REQUEST_CODE = 1007 ;
7478
7579 private DynamicIntroTheme dynamicTheme = new DynamicIntroTheme ();
7680 private DynamicLanguage dynamicLanguage = new DynamicLanguage ();
@@ -84,12 +88,12 @@ public class PassphrasePromptActivity extends PassphraseActivity {
8488 private ImageButton hideButton ;
8589 private AnimatingToggle visibilityToggle ;
8690
87- private FingerprintManagerCompat fingerprintManager ;
88- private CancellationSignal fingerprintCancellationSignal ;
89- private FingerprintListener fingerprintListener ;
91+ private BiometricManager biometricManager ;
92+ private BiometricPrompt biometricPrompt ;
93+ private BiometricPrompt . PromptInfo biometricPromptInfo ;
9094
9195 private boolean authenticated ;
92- private boolean failure ;
96+ private boolean hadFailure ;
9397
9498 @ Override
9599 public void onCreate (Bundle savedInstanceState ) {
@@ -112,20 +116,11 @@ public void onResume() {
112116
113117 setLockTypeVisibility ();
114118
115- if (TextSecurePreferences .isScreenLockEnabled (this ) && !authenticated && !failure ) {
119+ if (TextSecurePreferences .isScreenLockEnabled (this ) && !authenticated && !hadFailure ) {
116120 resumeScreenLock ();
117121 }
118122
119- failure = false ;
120- }
121-
122- @ Override
123- public void onPause () {
124- super .onPause ();
125-
126- if (TextSecurePreferences .isScreenLockEnabled (this )) {
127- pauseScreenLock ();
128- }
123+ hadFailure = false ;
129124 }
130125
131126 @ Override
@@ -160,15 +155,16 @@ public boolean onOptionsItemSelected(MenuItem item) {
160155 }
161156
162157 @ Override
163- @ SuppressLint ("MissingSuperCall" ) // no fragments to dispatch to
164- public void onActivityResult (int requestCode , int resultcode , Intent data ) {
165- if (requestCode != 1 ) return ;
158+ public void onActivityResult (int requestCode , int resultCode , Intent data ) {
159+ super .onActivityResult (requestCode , resultCode , data );
166160
167- if (resultcode == RESULT_OK ) {
161+ if (requestCode != AUTHENTICATE_REQUEST_CODE ) return ;
162+
163+ if (resultCode == RESULT_OK ) {
168164 handleAuthenticated ();
169165 } else {
170166 Log .w (TAG , "Authentication failed" );
171- failure = true ;
167+ hadFailure = true ;
172168 }
173169 }
174170
@@ -219,16 +215,20 @@ private void initializeResources() {
219215 ImageButton okButton = findViewById (R .id .ok_button );
220216 Toolbar toolbar = findViewById (R .id .toolbar );
221217
222- showButton = findViewById (R .id .passphrase_visibility );
223- hideButton = findViewById (R .id .passphrase_visibility_off );
224- visibilityToggle = findViewById (R .id .button_toggle );
225- passphraseText = findViewById (R .id .passphrase_edit );
226- passphraseAuthContainer = findViewById (R .id .password_auth_container );
227- fingerprintPrompt = findViewById (R .id .fingerprint_auth_container );
228- lockScreenButton = findViewById (R .id .lock_screen_auth_container );
229- fingerprintManager = FingerprintManagerCompat .from (this );
230- fingerprintCancellationSignal = new CancellationSignal ();
231- fingerprintListener = new FingerprintListener ();
218+ showButton = findViewById (R .id .passphrase_visibility );
219+ hideButton = findViewById (R .id .passphrase_visibility_off );
220+ visibilityToggle = findViewById (R .id .button_toggle );
221+ passphraseText = findViewById (R .id .passphrase_edit );
222+ passphraseAuthContainer = findViewById (R .id .password_auth_container );
223+ fingerprintPrompt = findViewById (R .id .fingerprint_auth_container );
224+ lockScreenButton = findViewById (R .id .lock_screen_auth_container );
225+ biometricManager = BiometricManager .from (this );
226+ biometricPrompt = new BiometricPrompt (this , new BiometricAuthenticationListener ());
227+ biometricPromptInfo = new BiometricPrompt .PromptInfo
228+ .Builder ()
229+ .setAllowedAuthenticators (ALLOWED_AUTHENTICATORS )
230+ .setTitle (getString (R .string .PassphrasePromptActivity_unlock_signal ))
231+ .build ();
232232
233233 setSupportActionBar (toolbar );
234234 getSupportActionBar ().setTitle ("" );
@@ -254,14 +254,9 @@ private void initializeResources() {
254254 private void setLockTypeVisibility () {
255255 if (TextSecurePreferences .isScreenLockEnabled (this )) {
256256 passphraseAuthContainer .setVisibility (View .GONE );
257-
258- if (fingerprintManager .isHardwareDetected () && fingerprintManager .hasEnrolledFingerprints ()) {
259- fingerprintPrompt .setVisibility (View .VISIBLE );
260- lockScreenButton .setVisibility (View .GONE );
261- } else {
262- fingerprintPrompt .setVisibility (View .GONE );
263- lockScreenButton .setVisibility (View .VISIBLE );
264- }
257+ fingerprintPrompt .setVisibility (biometricManager .canAuthenticate (BIOMETRIC_AUTHENTICATORS ) == BiometricManager .BIOMETRIC_SUCCESS ? View .VISIBLE
258+ : View .GONE );
259+ lockScreenButton .setVisibility (View .VISIBLE );
265260 } else {
266261 passphraseAuthContainer .setVisibility (View .VISIBLE );
267262 fingerprintPrompt .setVisibility (View .GONE );
@@ -280,26 +275,19 @@ private void resumeScreenLock() {
280275 return ;
281276 }
282277
283- if (fingerprintManager .isHardwareDetected () && fingerprintManager .hasEnrolledFingerprints ()) {
284- Log .i (TAG , "Listening for fingerprints..." );
285- fingerprintCancellationSignal = new CancellationSignal ();
286- fingerprintManager .authenticate (null , 0 , fingerprintCancellationSignal , fingerprintListener , null );
278+ if (biometricManager .canAuthenticate (ALLOWED_AUTHENTICATORS ) == BiometricManager .BIOMETRIC_SUCCESS ) {
279+ Log .i (TAG , "Listening for biometric authentication..." );
280+ biometricPrompt .authenticate (biometricPromptInfo );
287281 } else if (Build .VERSION .SDK_INT >= 21 ){
288282 Log .i (TAG , "firing intent..." );
289283 Intent intent = keyguardManager .createConfirmDeviceCredentialIntent (getString (R .string .PassphrasePromptActivity_unlock_signal ), "" );
290- startActivityForResult (intent , 1 );
284+ startActivityForResult (intent , AUTHENTICATE_REQUEST_CODE );
291285 } else {
292286 Log .w (TAG , "Not compatible..." );
293287 handleAuthenticated ();
294288 }
295289 }
296290
297- private void pauseScreenLock () {
298- if (fingerprintCancellationSignal != null ) {
299- fingerprintCancellationSignal .cancel ();
300- }
301- }
302-
303291 private void sendEmailToSupport () {
304292 String body = SupportEmailUtil .generateSupportEmailBody (this ,
305293 R .string .PassphrasePromptActivity_signal_android_lock_screen ,
@@ -359,15 +347,19 @@ protected void cleanup() {
359347 System .gc ();
360348 }
361349
362- private class FingerprintListener extends FingerprintManagerCompat .AuthenticationCallback {
350+ private class BiometricAuthenticationListener extends BiometricPrompt .AuthenticationCallback {
363351 @ Override
364- public void onAuthenticationError (int errMsgId , CharSequence errString ) {
365- Log .w (TAG , "Authentication error: " + errMsgId + " " + errString );
366- onAuthenticationFailed ();
352+ public void onAuthenticationError (int errorCode , @ NonNull CharSequence errorString ) {
353+ Log .w (TAG , "Authentication error: " + errorCode );
354+ hadFailure = true ;
355+
356+ if (errorCode != BiometricPrompt .ERROR_CANCELED && errorCode != BiometricPrompt .ERROR_USER_CANCELED ) {
357+ onAuthenticationFailed ();
358+ }
367359 }
368360
369361 @ Override
370- public void onAuthenticationSucceeded (FingerprintManagerCompat .AuthenticationResult result ) {
362+ public void onAuthenticationSucceeded (@ NonNull BiometricPrompt .AuthenticationResult result ) {
371363 Log .i (TAG , "onAuthenticationSucceeded" );
372364 fingerprintPrompt .setImageResource (R .drawable .ic_check_white_48dp );
373365 fingerprintPrompt .getBackground ().setColorFilter (getResources ().getColor (R .color .green_500 ), PorterDuff .Mode .SRC_IN );
@@ -384,8 +376,7 @@ public void onAnimationEnd(Animator animation) {
384376
385377 @ Override
386378 public void onAuthenticationFailed () {
387- Log .w (TAG , "onAuthenticatoinFailed()" );
388- FingerprintManagerCompat .AuthenticationCallback callback = this ;
379+ Log .w (TAG , "onAuthenticationFailed()" );
389380
390381 fingerprintPrompt .setImageResource (R .drawable .ic_close_white_48dp );
391382 fingerprintPrompt .getBackground ().setColorFilter (getResources ().getColor (R .color .red_500 ), PorterDuff .Mode .SRC_IN );
@@ -409,6 +400,5 @@ public void onAnimationRepeat(Animation animation) {}
409400
410401 fingerprintPrompt .startAnimation (shake );
411402 }
412-
413403 }
414404}
0 commit comments