Skip to content

Commit

Permalink
Fix fingerprint dialog behaviour after rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Zakharov committed Oct 11, 2019
1 parent 95fe0a2 commit a49d8b2
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.arch.lifecycle.Lifecycle;
Expand All @@ -35,12 +34,9 @@
import android.support.annotation.Nullable;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.util.Log;
import android.widget.Toast;

import java.lang.annotation.Retention;
import java.security.Signature;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import javax.crypto.Cipher;
Expand Down Expand Up @@ -184,7 +180,7 @@ Mac getMac() {
/**
* Callback structure provided to {@link BiometricPrompt}. Users of {@link
* BiometricPrompt} must provide an implementation of this for listening to
* fingerprint events.
* fingerprint Events.
*/
public abstract static class AuthenticationCallback {
/**
Expand Down Expand Up @@ -401,6 +397,8 @@ public boolean isDeviceCredentialAllowed() {
}
}

public static LifecycleEvents Events;

// Passed in from the client.
private Activity mActivity;
private Fragment mFragment;
Expand Down Expand Up @@ -454,7 +452,7 @@ public void run() {
*/
private final LifecycleObserver mLifecycleObserver = new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause() {
void onPause(Fragment fragment) {
if (!isChangingConfigurations() && !usingBiometricFragment()) {
// May be null if no authentication is occurring.
if (mFingerprintDialogFragment != null && mFingerprintHelperFragment != null) {
Expand All @@ -464,14 +462,22 @@ void onPause() {
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume() {
void onResume(Fragment fragment) {
if (!usingBiometricFragment()) {
mFingerprintDialogFragment =
(FingerprintDialogFragment) getFragmentManager().findFragmentByTag(
DIALOG_FRAGMENT_TAG);
mFingerprintHelperFragment =
(FingerprintHelperFragment) getFragmentManager().findFragmentByTag(
FINGERPRINT_HELPER_FRAGMENT_TAG);
FingerprintDialogFragment dialogFragment = (FingerprintDialogFragment) getFragmentManager().findFragmentByTag(
DIALOG_FRAGMENT_TAG);
if (dialogFragment == null && fragment instanceof FingerprintDialogFragment) {
dialogFragment = (FingerprintDialogFragment) fragment;
}
FingerprintHelperFragment helperFragment = (FingerprintHelperFragment) getFragmentManager().findFragmentByTag(
FINGERPRINT_HELPER_FRAGMENT_TAG);

if (dialogFragment == null || helperFragment == null) {
return;
}

mFingerprintDialogFragment = dialogFragment;
mFingerprintHelperFragment = helperFragment;

if (DEBUG) Log.v(TAG, "FingerprintDialogFragment: " + mFingerprintDialogFragment);
if (DEBUG) Log.v(TAG, "FingerprintHelperFragment: " + mFingerprintHelperFragment);
Expand Down Expand Up @@ -501,8 +507,8 @@ void onResume() {
* {@link AuthenticationCallback} after configuration changes.
*
* @param activity A reference to the client's activity.
* @param executor An executor to handle callback events.
* @param callback An object to receive authentication events.
* @param executor An executor to handle callback Events.
* @param callback An object to receive authentication Events.
*/
@SuppressLint("LambdaLast")
public BiometricPrompt(@NonNull Activity activity,
Expand All @@ -520,6 +526,8 @@ public BiometricPrompt(@NonNull Activity activity,
mActivity = activity;
mAuthenticationCallback = callback;
mExecutor = executor;

Events = new LifecycleEvents(mLifecycleObserver);
}

/**
Expand All @@ -534,8 +542,8 @@ public BiometricPrompt(@NonNull Activity activity,
* such as {@link Fragment#onCreate(Bundle)}.
*
* @param fragment A reference to the client's fragment.
* @param executor An executor to handle callback events.
* @param callback An object to receive authentication events.
* @param executor An executor to handle callback Events.
* @param callback An object to receive authentication Events.
*/
@SuppressLint("LambdaLast")
public BiometricPrompt(@NonNull Fragment fragment,
Expand All @@ -552,6 +560,8 @@ public BiometricPrompt(@NonNull Fragment fragment,
mFragment = fragment;
mAuthenticationCallback = callback;
mExecutor = executor;

Events = new LifecycleEvents(mLifecycleObserver);
}

/**
Expand Down Expand Up @@ -640,7 +650,7 @@ public void onAuthenticationFailed() {
if (fingerprintDialogFragment != null) {
mFingerprintDialogFragment = fingerprintDialogFragment;
} else {
mFingerprintDialogFragment = FingerprintDialogFragment.newInstance(mLifecycleObserver);
mFingerprintDialogFragment = FingerprintDialogFragment.newInstance();
}

mFingerprintDialogFragment.setNegativeButtonListener(mNegativeButtonListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
Expand All @@ -46,8 +44,6 @@
import android.widget.ImageView;
import android.widget.TextView;

import java.lang.reflect.Method;

/**
* This class implements a custom AlertDialog that prompts the user for fingerprint authentication.
* This class is not meant to be preserved across process death; for security reasons, the
Expand All @@ -58,31 +54,6 @@
@SuppressLint("SyntheticAccessor")
public class FingerprintDialogFragment extends DialogFragment {

private static class Events {
LifecycleObserver observer;
Events(LifecycleObserver observer) {
this.observer = observer;
}

void raise(Lifecycle.Event event) {
Method[] methods = observer.getClass().getDeclaredMethods();
for(Method mt : methods) {
if (mt.isAnnotationPresent(OnLifecycleEvent.class)) {
OnLifecycleEvent annotation = mt.getAnnotation(OnLifecycleEvent.class);
if (annotation.value() == event) {
try {
mt.invoke(observer);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
}

private static Events events;

private static final String TAG = "FingerprintDialogFrag";
private static final String KEY_DIALOG_BUNDLE = "SavedBundle";

Expand Down Expand Up @@ -117,9 +88,8 @@ void raise(Lifecycle.Event event) {
/**
* Creates a dialog requesting for Fingerprint authentication.
*/
static FingerprintDialogFragment newInstance(LifecycleObserver observer) {
static FingerprintDialogFragment newInstance() {
FingerprintDialogFragment fragment = new FingerprintDialogFragment();
events = new Events(observer);
return fragment;
}

Expand Down Expand Up @@ -239,7 +209,6 @@ public void onSaveInstanceState(@NonNull Bundle outState) {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
events.raise(Lifecycle.Event.ON_CREATE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mErrorColor = getThemedColorFor(android.R.attr.colorError);
Expand All @@ -254,15 +223,15 @@ public void onResume() {
super.onResume();
mLastState = STATE_NONE;
updateFingerprintIcon(STATE_FINGERPRINT);
events.raise(Lifecycle.Event.ON_RESUME);
BiometricPrompt.Events.raise(Lifecycle.Event.ON_RESUME, this);
}

@Override
public void onPause() {
super.onPause();
// Remove everything since the fragment is going away.
mHandler.removeCallbacksAndMessages(null);
events.raise(Lifecycle.Event.ON_PAUSE);
BiometricPrompt.Events.raise(Lifecycle.Event.ON_PAUSE, this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import android.annotation.SuppressLint;
import android.app.Fragment;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
Expand Down Expand Up @@ -259,6 +261,18 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
mContext = getActivity();
}

@Override
public void onResume() {
super.onResume();
BiometricPrompt.Events.raise(Lifecycle.Event.ON_RESUME, this);
}

@Override
public void onPause() {
super.onPause();
BiometricPrompt.Events.raise(Lifecycle.Event.ON_PAUSE, this);
}

@Override
@SuppressWarnings("deprecation")
@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.exxbrain.android.biometric;

import android.app.Fragment;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.OnLifecycleEvent;

import java.lang.reflect.Method;

class LifecycleEvents {
LifecycleObserver observer;
LifecycleEvents(LifecycleObserver observer) {
this.observer = observer;
}

void raise(Lifecycle.Event event, Fragment fragment) {
Method[] methods = observer.getClass().getDeclaredMethods();
for(Method mt : methods) {
if (mt.isAnnotationPresent(OnLifecycleEvent.class)) {
OnLifecycleEvent annotation = mt.getAnnotation(OnLifecycleEvent.class);
if (annotation.value() == event) {
try {
mt.invoke(observer, fragment);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
}

0 comments on commit a49d8b2

Please sign in to comment.