Merge "Launch Face Settings when device enrolled face" into tm-qpr-dev
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 730e049..cdd2d8b 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -183,7 +183,9 @@
         mUserManager = UserManager.get(this);
         updatePasswordQuality();
 
-        if (!mConfirmingCredentials) {
+        // Check isFinishing() because FaceEnrollIntroduction may finish self to launch
+        // FaceSettings during onCreate()
+        if (!mConfirmingCredentials && !isFinishing()) {
             if (!mHasPassword) {
                 // No password registered, launch into enrollment wizard.
                 mConfirmingCredentials = true;
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index a123308..66ed56a 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -28,6 +28,7 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.face.FaceManager;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.text.Html;
 import android.text.method.LinkMovementMethod;
 import android.util.Log;
@@ -42,6 +43,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
+import com.android.settings.Settings;
 import com.android.settings.Utils;
 import com.android.settings.biometrics.BiometricEnrollActivity;
 import com.android.settings.biometrics.BiometricEnrollIntroduction;
@@ -110,8 +112,26 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        mFaceManager = getFaceManager();
+
+        if (savedInstanceState == null
+                && !WizardManagerHelper.isAnySetupWizard(getIntent())
+                && !getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false)
+                && maxFacesEnrolled()) {
+            // from tips && maxEnrolled
+            Log.d(TAG, "launch face settings");
+            launchFaceSettingsActivity();
+            finish();
+        }
+
         super.onCreate(savedInstanceState);
 
+        // Wait super::onCreated() then return because SuperNotCalledExceptio will be thrown
+        // if we don't wait for it.
+        if (isFinishing()) {
+            return;
+        }
+
         // Apply extracted theme color to icons.
         final ImageView iconGlasses = findViewById(R.id.icon_glasses);
         final ImageView iconLooking = findViewById(R.id.icon_looking);
@@ -152,8 +172,6 @@
             infoMessageRequireEyes.setText(getInfoMessageRequireEyes());
         }
 
-        mFaceManager = getFaceManager();
-
         // This path is an entry point for SetNewPasswordController, e.g.
         // adb shell am start -a android.app.action.SET_NEW_PASSWORD
         if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
@@ -191,6 +209,24 @@
         Log.v(TAG, "cameraPrivacyEnabled : " + cameraPrivacyEnabled);
     }
 
+    private void launchFaceSettingsActivity() {
+        final Intent intent = new Intent(this, Settings.FaceSettingsInternalActivity.class);
+        final byte[] token = getIntent().getByteArrayExtra(
+                ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+        if (token != null) {
+            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
+        }
+        final int userId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
+        if (userId != UserHandle.USER_NULL) {
+            intent.putExtra(Intent.EXTRA_USER_ID, userId);
+        }
+        BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
+        intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true);
+        intent.putExtra(EXTRA_KEY_CHALLENGE, getIntent().getLongExtra(EXTRA_KEY_CHALLENGE, -1L));
+        intent.putExtra(EXTRA_KEY_SENSOR_ID, getIntent().getIntExtra(EXTRA_KEY_SENSOR_ID, -1));
+        startActivity(intent);
+    }
+
     @VisibleForTesting
     @Nullable
     protected FaceManager getFaceManager() {
@@ -232,6 +268,15 @@
     @Override
     protected void onStart() {
         super.onStart();
+        listenFoldEventForPostureGuidance();
+    }
+
+    private void listenFoldEventForPostureGuidance() {
+        if (maxFacesEnrolled()) {
+            Log.d(TAG, "Device has enrolled face, do not show posture guidance");
+            return;
+        }
+
         if (getPostureGuidanceIntent() == null) {
             Log.d(TAG, "Device do not support posture guidance");
             return;
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
index 6c04add..9d58855 100644
--- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java
@@ -51,6 +51,8 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.biometrics.BiometricEnrollBase;
 import com.android.settings.biometrics.BiometricUtils;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.testutils.FakeFeatureFactory;
@@ -62,6 +64,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;
 import com.google.android.setupdesign.view.BottomScrollView;
 
@@ -168,6 +171,7 @@
     @After
     public void tearDown() {
         ShadowUtils.reset();
+        ShadowLockPatternUtils.reset();
     }
 
     private void setupActivity() {
@@ -315,7 +319,7 @@
     }
 
     @Test
-    public void testFaceEnrollEducation_hasBottomScrollView() {
+    public void testFaceEnrollIntroduction_hasBottomScrollView() {
         setupActivity();
         BottomScrollView scrollView = getGlifLayout(mActivity).findViewById(R.id.sud_scroll_view);
 
@@ -387,7 +391,7 @@
     }
 
     @Test
-    public void testFaceEnrollEducation_onFoldedUpdated_folded() {
+    public void testFaceEnrollIntroduction_onFoldedUpdated_folded() {
         final Configuration newConfig = new Configuration();
         newConfig.smallestScreenWidthDp = DENSITY_DEFAULT;
         setupActivityForPosture();
@@ -400,4 +404,97 @@
 
         assertThat(mSpyActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_CLOSED);
     }
+
+    @Test
+    public void testFaceEnrollIntroduction_maxFacesEnrolled_launchFaceSettings() {
+        setFaceManagerToHave(1 /* numEnrollments */);
+        final Intent intent = new Intent();
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+        mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+        mActivity = (TestFaceEnrollIntroduction) mController.get();
+        mActivity.mOverrideFaceManager = mFaceManager;
+
+        mController.create();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+        final Intent nextStartedActivity = shadowActivity.getNextStartedActivity();
+        assertThat(nextStartedActivity).isNotNull();
+        assertThat(nextStartedActivity.getComponent().getClassName())
+                .isEqualTo(Settings.FaceSettingsInternalActivity.class.getName());
+    }
+
+    @Test
+    public void testFaceEnrollIntroduction_maxFacesEnrolled_isSuw_notLaunchFaceSettings() {
+        setFaceManagerToHave(1 /* numEnrollments */);
+        ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC);
+        final Intent intent = new Intent();
+        intent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true);
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+        mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+        mActivity = (TestFaceEnrollIntroduction) mController.get();
+        mActivity.mOverrideFaceManager = mFaceManager;
+
+        mController.create();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+        final Intent nextStartedActivity = shadowActivity.getNextStartedActivity();
+        assertThat(nextStartedActivity).isNull();
+    }
+
+    @Test
+    public void testFaceEnrollIntroduction_maxFacesEnrolled_fromSettings_notLaunchFaceSettings() {
+        setFaceManagerToHave(1 /* numEnrollments */);
+        ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC);
+        final Intent intent = new Intent();
+        intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true);
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+        mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+        mActivity = (TestFaceEnrollIntroduction) mController.get();
+        mActivity.mOverrideFaceManager = mFaceManager;
+
+        mController.create();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+        final Intent nextStartedActivity = shadowActivity.getNextStartedActivity();
+        assertThat(nextStartedActivity).isNull();
+    }
+
+    @Test
+    public void testFaceEnrollIntroduction_hasPostureCallback() {
+        when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any()))
+                .thenReturn(new Intent());
+        setFaceManagerToHave(0 /* numEnrollments */);
+        ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC);
+        final Intent intent = new Intent();
+        intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true);
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+        mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+        mActivity = (TestFaceEnrollIntroduction) mController.get();
+        mActivity.mOverrideFaceManager = mFaceManager;
+
+        mController.create();
+        mController.start();
+
+        assertThat(mActivity.getPostureCallback()).isNotNull();
+    }
+
+    @Test
+    public void testFaceEnrollIntroduction_maxFacesEnrolled_noPostureCallback() {
+        when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any()))
+                .thenReturn(new Intent());
+        setFaceManagerToHave(1 /* numEnrollments */);
+        ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC);
+        final Intent intent = new Intent();
+        intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true);
+        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+        mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent);
+        mActivity = (TestFaceEnrollIntroduction) mController.get();
+        mActivity.mOverrideFaceManager = mFaceManager;
+
+        mController.create();
+        mController.start();
+
+        assertThat(mActivity.getPostureCallback()).isNull();
+    }
+
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index 74e3971..9a83b59 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -36,6 +36,7 @@
 public class ShadowLockPatternUtils {
 
     private static boolean sDeviceEncryptionEnabled;
+    private static Map<Integer, Integer> sUserToActivePasswordQualityMap = new HashMap<>();
     private static Map<Integer, Integer> sUserToComplexityMap = new HashMap<>();
     private static Map<Integer, Integer> sUserToProfileComplexityMap = new HashMap<>();
     private static Map<Integer, PasswordMetrics> sUserToMetricsMap = new HashMap<>();
@@ -44,6 +45,7 @@
 
     @Resetter
     public static void reset() {
+        sUserToActivePasswordQualityMap.clear();
         sUserToComplexityMap.clear();
         sUserToProfileComplexityMap.clear();
         sUserToMetricsMap.clear();
@@ -72,7 +74,11 @@
 
     @Implementation
     protected int getActivePasswordQuality(int userId) {
-        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        final Integer activePasswordQuality = sUserToActivePasswordQualityMap.get(userId);
+        if (activePasswordQuality == null) {
+            return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        }
+        return activePasswordQuality;
     }
 
     @Implementation
@@ -153,6 +159,10 @@
         sUserToProfileMetricsMap.put(UserHandle.myUserId(), metrics);
     }
 
+    public static void setActivePasswordQuality(int quality) {
+        sUserToActivePasswordQualityMap.put(UserHandle.myUserId(), quality);
+    }
+
     @Implementation
     public boolean isLockScreenDisabled(int userId) {
         return false;