Finish biometric enroll screens when backgrounded

Currently, there are some biometric security setting and enrollment
screens which remain open after the user has backgrounded them. This
means that they can later be resumed without requiring the user to
confirm their device credential as normal.

This commit fixes the issue in AOSP by adding logic to the affected
biometric enrollment/setting activities in to finish() with
RESULT_TIMEOUT in onStop(). We don't want to finish() these activities
prematurely if the user is currently in a wizard setup flow, however. In
that case, this commit ensures that the newly added logic will not run.

Test: Pixel 3 - Background at each step of fingerprint enroll => finish
Test: Pixel 3 - Rotate at each step of fingerprint enroll => no finish
Test: Pixel 3 - Proceed though fingerprint setup wizard => no change

Bug: 142544519
Change-Id: I8ec0fa1e30bafe097d9dc82991ff786ebf24844b
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index c23aee6..308878f 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -36,6 +36,7 @@
 
 import com.google.android.setupcompat.template.FooterBarMixin;
 import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupcompat.util.WizardManagerHelper;
 import com.google.android.setupdesign.GlifLayout;
 
 /**
@@ -120,6 +121,19 @@
         initViews();
     }
 
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (!isChangingConfigurations() && shouldFinishWhenBackgrounded()) {
+            setResult(RESULT_TIMEOUT);
+            finish();
+        }
+    }
+
+    protected boolean shouldFinishWhenBackgrounded() {
+        return !WizardManagerHelper.isAnySetupWizard(getIntent());
+    }
+
     protected void initViews() {
         getWindow().setStatusBarColor(Color.TRANSPARENT);
     }
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index d94686e..d815f57 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -178,6 +178,11 @@
         }
     }
 
+    @Override
+    protected boolean shouldFinishWhenBackgrounded() {
+        return super.shouldFinishWhenBackgrounded() && !mConfirmingCredentials && !mNextClicked;
+    }
+
     private void updatePasswordQuality() {
         final int passwordQuality = new ChooseLockSettingsHelper(this).utils()
                 .getActivePasswordQuality(mUserManager.getCredentialOwnerProfile(mUserId));
@@ -243,7 +248,8 @@
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
-            if (resultCode == RESULT_FINISHED || resultCode == RESULT_SKIP) {
+            if (resultCode == RESULT_FINISHED || resultCode == RESULT_SKIP
+                    || resultCode == RESULT_TIMEOUT) {
                 setResult(resultCode, data);
                 finish();
                 return;
diff --git a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
index a246055..17a933b 100644
--- a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
@@ -23,6 +23,8 @@
 import com.android.settings.R;
 import com.android.settings.password.ChooseLockSettingsHelper;
 
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
 /**
  * Abstract base activity which handles the actual enrolling for biometrics.
  */
@@ -58,7 +60,6 @@
 
     @Override
     protected void onStop() {
-        super.onStop();
         if (mSidecar != null) {
             mSidecar.setListener(null);
         }
@@ -69,6 +70,9 @@
                 getSupportFragmentManager()
                         .beginTransaction().remove(mSidecar).commitAllowingStateLoss();
             }
+            if (!WizardManagerHelper.isAnySetupWizard(getIntent())) {
+                setResult(RESULT_TIMEOUT);
+            }
             finish();
         }
     }
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
index e1253c1..3b84c35 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java
@@ -16,17 +16,13 @@
 
 package com.android.settings.biometrics.face;
 
-import static android.security.KeyStore.getApplicationContext;
-
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.hardware.face.FaceManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
@@ -173,14 +169,8 @@
     }
 
     @Override
-    protected void onStop() {
-        super.onStop();
-
-        if (!isChangingConfigurations() && !WizardManagerHelper.isAnySetupWizard(getIntent())
-                && !mNextClicked) {
-            setResult(RESULT_SKIP);
-            finish();
-        }
+    protected boolean shouldFinishWhenBackgrounded() {
+        return super.shouldFinishWhenBackgrounded() && !mNextClicked;
     }
 
     @Override
@@ -216,11 +206,13 @@
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
         mResultIntent = data;
         if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
             // If the user finished or skipped enrollment, finish this activity
-            if (resultCode == RESULT_SKIP || resultCode == RESULT_FINISHED) {
-                setResult(resultCode);
+            if (resultCode == RESULT_FINISHED || resultCode == RESULT_SKIP
+                    || resultCode == RESULT_TIMEOUT) {
+                setResult(resultCode, data);
                 finish();
             }
         }
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index 073c7e6..6709a6a 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -100,16 +100,6 @@
     }
 
     @Override
-    protected void onStop() {
-        super.onStop();
-
-        if (!isChangingConfigurations() && !mConfirmingCredentials && !mNextClicked
-                && !WizardManagerHelper.isAnySetupWizard(getIntent())) {
-            finish();
-        }
-    }
-
-    @Override
     protected boolean isDisabledByAdmin() {
         return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 this, DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null;
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index 5795e65..e1ca4f7 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -19,7 +19,9 @@
 import static android.app.Activity.RESULT_OK;
 
 import static com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST;
+import static com.android.settings.biometrics.BiometricEnrollBase.ENROLL_REQUEST;
 import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED;
+import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT;
 
 import android.app.settings.SettingsEnums;
 import android.content.Context;
@@ -90,6 +92,9 @@
         mEnrollButton.setVisible(true);
     };
 
+    private final FaceSettingsEnrollButtonPreferenceController.Listener mEnrollListener = intent ->
+            startActivityForResult(intent, ENROLL_REQUEST);
+
     public static boolean isAvailable(Context context) {
         FaceManager manager = Utils.getFaceManagerOrNull(context);
         return manager != null && manager.isHardwareDetected();
@@ -230,11 +235,16 @@
                     }
                 }
             }
+        } else if (requestCode == ENROLL_REQUEST) {
+            if (resultCode == RESULT_TIMEOUT) {
+                setResult(resultCode, data);
+                finish();
+            }
         }
 
         if (mToken == null) {
             // Didn't get an authentication, finishing
-            getActivity().finish();
+            finish();
         }
     }
 
@@ -252,7 +262,7 @@
                 }
                 mToken = null;
             }
-            getActivity().finish();
+            finish();
         }
     }
 
@@ -277,6 +287,7 @@
                 mRemoveController.setActivity((SettingsActivity) getActivity());
             } else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
                 mEnrollController = (FaceSettingsEnrollButtonPreferenceController) controller;
+                mEnrollController.setListener(mEnrollListener);
                 mEnrollController.setActivity((SettingsActivity) getActivity());
             }
         }
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
index a087ccc..e89eca4 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
@@ -43,6 +43,7 @@
     private SettingsActivity mActivity;
     private Button mButton;
     private boolean mIsClicked;
+    private Listener mListener;
 
     public FaceSettingsEnrollButtonPreferenceController(Context context) {
         this(context, KEY);
@@ -69,7 +70,11 @@
         intent.setClassName("com.android.settings", FaceEnrollIntroduction.class.getName());
         intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
-        mContext.startActivity(intent);
+        if (mListener != null) {
+            mListener.onStartEnrolling(intent);
+        } else {
+            mContext.startActivity(intent);
+        }
     }
 
     @Override
@@ -95,4 +100,19 @@
     public void setActivity(SettingsActivity activity) {
         mActivity = activity;
     }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Interface for registering callbacks related to the face enroll preference button.
+     */
+    public interface Listener {
+        /**
+         * Called when the user has indicated an intent to begin enrolling a new face.
+         * @param intent The Intent that should be used to launch face enrollment.
+         */
+        void onStartEnrolling(Intent intent);
+    }
 }
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index e92c967..8194878 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -222,8 +222,8 @@
 
     @Override
     protected void onStop() {
-        super.onStop();
         stopIconAnimation();
+        super.onStop();
     }
 
     private void animateProgress(int progress) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 733fb3f..9508268 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -115,10 +115,15 @@
 
     @Override
     protected void onStop() {
-        super.onStop();
         if (mAnimation != null) {
             mAnimation.pauseAnimation();
         }
+        super.onStop();
+    }
+
+    @Override
+    protected boolean shouldFinishWhenBackgrounded() {
+        return super.shouldFinishWhenBackgrounded() && !mNextClicked;
     }
 
     @Override
@@ -163,26 +168,25 @@
                 finish();
             }
         } else if (requestCode == ENROLL_REQUEST) {
-            if (resultCode == RESULT_FINISHED) {
-                setResult(RESULT_FINISHED);
-                finish();
-            } else if (resultCode == RESULT_SKIP) {
-                setResult(RESULT_SKIP);
-                finish();
-            } else if (resultCode == RESULT_TIMEOUT) {
-                setResult(RESULT_TIMEOUT);
-                finish();
-            } else {
-                FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
-                int enrolled = fpm.getEnrolledFingerprints().size();
-                int max = getResources().getInteger(
-                        com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
-                if (enrolled >= max) {
+            switch (resultCode) {
+                case RESULT_FINISHED:
+                case RESULT_SKIP:
+                case RESULT_TIMEOUT:
+                    setResult(resultCode);
                     finish();
-                } else {
-                    // We came back from enrolling but it wasn't completed, start again.
-                    startLookingForFingerprint();
-                }
+                    break;
+                default:
+                    FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
+                    int enrolled = fpm.getEnrolledFingerprints().size();
+                    int max = getResources().getInteger(
+                            com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
+                    if (enrolled >= max) {
+                        finish();
+                    } else {
+                        // We came back from enrolling but it wasn't completed, start again.
+                        startLookingForFingerprint();
+                    }
+                    break;
             }
         } else {
             super.onActivityResult(requestCode, resultCode, data);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 68b21f5..1a8e481 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -133,6 +133,7 @@
         private Drawable mHighlightDrawable;
         private int mUserId;
         private CharSequence mFooterTitle;
+        private boolean mEnrollClicked;
 
         private static final String TAG_AUTHENTICATE_SIDECAR = "authenticate_sidecar";
         private static final String TAG_REMOVAL_SIDECAR = "removal_sidecar";
@@ -464,6 +465,14 @@
         }
 
         @Override
+        public void onStop() {
+            super.onStop();
+            if (!getActivity().isChangingConfigurations() && !mLaunchedConfirm && !mEnrollClicked) {
+                getActivity().finish();
+            }
+        }
+
+        @Override
         public void onSaveInstanceState(final Bundle outState) {
             outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
                     mToken);
@@ -475,6 +484,7 @@
         public boolean onPreferenceTreeClick(Preference pref) {
             final String key = pref.getKey();
             if (KEY_FINGERPRINT_ADD.equals(key)) {
+                mEnrollClicked = true;
                 Intent intent = new Intent();
                 intent.setClassName(SETTINGS_PACKAGE_NAME,
                         FingerprintEnrollEnrolling.class.getName());
@@ -564,9 +574,10 @@
                     }
                 }
             } else if (requestCode == ADD_FINGERPRINT_REQUEST) {
+                mEnrollClicked = false;
                 if (resultCode == RESULT_TIMEOUT) {
                     Activity activity = getActivity();
-                    activity.setResult(RESULT_TIMEOUT);
+                    activity.setResult(resultCode);
                     activity.finish();
                 }
             }