diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7330f1e3490..7034dc3580b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1710,6 +1710,11 @@ + + diff --git a/res/layout/choose_lock_generic_fingerprint_header.xml b/res/layout/choose_lock_generic_fingerprint_header.xml index 5ad3004d0f2..6a107bf06d5 100644 --- a/res/layout/choose_lock_generic_fingerprint_header.xml +++ b/res/layout/choose_lock_generic_fingerprint_header.xml @@ -15,6 +15,7 @@ --> + style="@style/FingerprintHeaderStyle" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index ef9c3dd712a..b1180c423e0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1102,6 +1102,12 @@ Fingerprint + Password + + Continue without fingerprint + + + You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock. + Disabled by administrator, encryption policy, or credential storage diff --git a/res/values/styles.xml b/res/values/styles.xml index 6d7a40ca053..32c0b4d48e8 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -439,4 +439,10 @@ 56dp + + diff --git a/res/xml/security_settings_picker.xml b/res/xml/security_settings_picker.xml index 7b6069d3360..6b52156dc31 100644 --- a/res/xml/security_settings_picker.xml +++ b/res/xml/security_settings_picker.xml @@ -47,4 +47,9 @@ android:key="unlock_set_managed" android:persistent="false"/> + + diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java index f650faee9cf..4ed080d2bd9 100644 --- a/src/com/android/settings/ChooseLockGeneric.java +++ b/src/com/android/settings/ChooseLockGeneric.java @@ -16,6 +16,11 @@ package com.android.settings; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD; +import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; +import static com.android.settings.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED; +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Activity; import android.app.AlertDialog; @@ -41,17 +46,18 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.fingerprint.FingerprintEnrollBase; +import com.android.settings.fingerprint.FingerprintEnrollFindSensor; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; import java.util.List; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - public class ChooseLockGeneric extends SettingsActivity { public static final String CONFIRM_CREDENTIALS = "confirm_credentials"; @@ -61,8 +67,8 @@ public class ChooseLockGeneric extends SettingsActivity { modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName()); String action = modIntent.getAction(); - if (DevicePolicyManager.ACTION_SET_NEW_PASSWORD.equals(action) - || DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) { + if (ACTION_SET_NEW_PASSWORD.equals(action) + || ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) { modIntent.putExtra(EXTRA_HIDE_DRAWER, true); } return modIntent; @@ -90,6 +96,7 @@ public class ChooseLockGeneric extends SettingsActivity { private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password"; private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern"; private static final String KEY_UNLOCK_SET_MANAGED = "unlock_set_managed"; + private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint"; private static final String PASSWORD_CONFIRMED = "password_confirmed"; private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; @@ -101,6 +108,8 @@ public class ChooseLockGeneric extends SettingsActivity { private static final int CONFIRM_EXISTING_REQUEST = 100; private static final int ENABLE_ENCRYPTION_REQUEST = 101; private static final int CHOOSE_LOCK_REQUEST = 102; + private static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103; + private static final int SKIP_FINGERPRINT_REQUEST = 104; private ChooseLockSettingsHelper mChooseLockSettingsHelper; private DevicePolicyManager mDPM; @@ -119,6 +128,7 @@ public class ChooseLockGeneric extends SettingsActivity { private int mUserId; private boolean mHideDrawer = false; private ManagedLockPasswordProvider mManagedPasswordProvider; + private boolean mIsSetNewPassword = false; protected boolean mForFingerprint = false; @@ -131,12 +141,15 @@ public class ChooseLockGeneric extends SettingsActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + String chooseLockAction = getActivity().getIntent().getAction(); mFingerprintManager = (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE); mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); mKeyStore = KeyStore.getInstance(); mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); mLockPatternUtils = new LockPatternUtils(getActivity()); + mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) + || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction); // Defaults to needing to confirm credentials final boolean confirmCredentials = getActivity().getIntent() @@ -154,6 +167,16 @@ public class ChooseLockGeneric extends SettingsActivity { ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); + if (mIsSetNewPassword) { + // In ACTION_SET_NEW_PARENT_PROFILE_PASSWORD or ACTION_SET_NEW_PASSWORD, the user + // will be asked to confirm the password if one has been set. + // On fingerprint supported device, fingerprint options are represented in the + // options. If the user chooses to skip fingerprint setup, ChooseLockGeneric is + // relaunched to only show options without fingerprint. In this case, we shouldn't + // ask the user to confirm the password again. + mPasswordConfirmed = getActivity().getIntent().getBooleanExtra( + PASSWORD_CONFIRMED, false); + } if (savedInstanceState != null) { mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); @@ -168,9 +191,8 @@ public class ChooseLockGeneric extends SettingsActivity { UserManager.get(getActivity()), null, getActivity().getIntent().getExtras()).getIdentifier(); - if (DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals( - getActivity().getIntent().getAction()) || - !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) { + if (ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) + || !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) { // Always use parent if explicitely requested or if profile challenge is not // supported Bundle arguments = getArguments(); @@ -180,8 +202,7 @@ public class ChooseLockGeneric extends SettingsActivity { mUserId = targetUser; } - if (DevicePolicyManager.ACTION_SET_NEW_PASSWORD - .equals(getActivity().getIntent().getAction()) + if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction) && UserManager.get(getActivity()).isManagedProfile(mUserId) && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { getActivity().setTitle(R.string.lock_settings_picker_title_profile); @@ -216,6 +237,10 @@ public class ChooseLockGeneric extends SettingsActivity { protected void addHeaderView() { if (mForFingerprint) { setHeaderView(R.layout.choose_lock_generic_fingerprint_header); + if (mIsSetNewPassword) { + ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description)) + .setText(R.string.fingerprint_unlock_title); + } } } @@ -228,6 +253,12 @@ public class ChooseLockGeneric extends SettingsActivity { // unlock method to an insecure one showFactoryResetProtectionWarningDialog(key); return true; + } else if (KEY_SKIP_FINGERPRINT.equals(key)) { + Intent chooseLockGenericIntent = new Intent(getActivity(), ChooseLockGeneric.class); + chooseLockGenericIntent.setAction(getIntent().getAction()); + chooseLockGenericIntent.putExtra(PASSWORD_CONFIRMED, mPasswordConfirmed); + startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST); + return true; } else { return setUnlockMethod(key); } @@ -302,6 +333,20 @@ public class ChooseLockGeneric extends SettingsActivity { getActivity().setResult(resultCode, data); finish(); } + } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST + && resultCode == FingerprintEnrollBase.RESULT_FINISHED) { + Intent intent = new Intent(getActivity(), FingerprintEnrollFindSensor.class); + if (data != null) { + intent.putExtras(data.getExtras()); + } + startActivity(intent); + finish(); + } else if (requestCode == SKIP_FINGERPRINT_REQUEST) { + if (resultCode != RESULT_CANCELED) { + getActivity().setResult( + resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data); + finish(); + } } else { getActivity().setResult(Activity.RESULT_CANCELED); finish(); @@ -375,6 +420,10 @@ public class ChooseLockGeneric extends SettingsActivity { } else { removePreference(KEY_UNLOCK_SET_MANAGED); } + + if (!(mForFingerprint && mIsSetNewPassword)) { + removePreference(KEY_SKIP_FINGERPRINT); + } } private void updateCurrentPreference() { @@ -612,7 +661,10 @@ public class ChooseLockGeneric extends SettingsActivity { quality = upgradeQuality(quality); Intent intent = getIntentForUnlockMethod(quality, disabled); if (intent != null) { - startActivityForResult(intent, CHOOSE_LOCK_REQUEST); + startActivityForResult(intent, + mIsSetNewPassword && mHasChallenge + ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST + : CHOOSE_LOCK_REQUEST); return; } @@ -620,8 +672,8 @@ public class ChooseLockGeneric extends SettingsActivity { mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, true, mUserPassword); mChooseLockSettingsHelper.utils().clearLock(mUserId); mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId); - removeAllFingerprintForUserAndFinish(mUserId); getActivity().setResult(Activity.RESULT_OK); + removeAllFingerprintForUserAndFinish(mUserId); } else { removeAllFingerprintForUserAndFinish(mUserId); } diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollBase.java b/src/com/android/settings/fingerprint/FingerprintEnrollBase.java index 65cc92e79e3..d58180428a9 100644 --- a/src/com/android/settings/fingerprint/FingerprintEnrollBase.java +++ b/src/com/android/settings/fingerprint/FingerprintEnrollBase.java @@ -36,7 +36,7 @@ import com.android.setupwizardlib.GlifLayout; */ public abstract class FingerprintEnrollBase extends InstrumentedActivity implements View.OnClickListener { - static final int RESULT_FINISHED = FingerprintSettings.RESULT_FINISHED; + public static final int RESULT_FINISHED = FingerprintSettings.RESULT_FINISHED; static final int RESULT_SKIP = FingerprintSettings.RESULT_SKIP; static final int RESULT_TIMEOUT = FingerprintSettings.RESULT_TIMEOUT; diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java new file mode 100644 index 00000000000..7cdf006746a --- /dev/null +++ b/src/com/android/settings/password/SetNewPasswordActivity.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.password; + +import android.annotation.Nullable; +import android.app.Activity; +import android.app.admin.DevicePolicyManager; +import android.content.Intent; +import android.os.Bundle; + +import com.android.settings.ChooseLockGeneric; + +/** + * Trampolines {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} and + * {@link DevicePolicyManager#ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} intent to the appropriate UI + * activity for handling set new password. + */ +public class SetNewPasswordActivity extends Activity implements SetNewPasswordController.Ui { + private String mNewPasswordAction; + private SetNewPasswordController mSetNewPasswordController; + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + + mNewPasswordAction = getIntent().getAction(); + mSetNewPasswordController = new SetNewPasswordController(this, this); + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + } + + @Override + public void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras) { + Intent intent = new Intent(this, ChooseLockGeneric.class) + .setAction(mNewPasswordAction); + if (chooseLockFingerprintExtras != null) { + intent.putExtras(chooseLockFingerprintExtras); + } + startActivity(intent); + finish(); + } +} diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java new file mode 100644 index 00000000000..470723b12f8 --- /dev/null +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.password; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.fingerprint.FingerprintManager; +import android.os.Bundle; +import android.os.UserHandle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.ChooseLockGeneric; +import com.android.settings.ChooseLockSettingsHelper; + +/** + * Business logic for {@link SetNewPasswordActivity}. + * + *

On devices that supports fingerprint, this controller directs the user to configure + * fingerprint + a backup password if the device admin allows fingerprint for keyguard and + * the user has never configured a fingerprint before. + */ +final class SetNewPasswordController { + + interface Ui { + /** Starts the {@link ChooseLockGeneric} activity with the given extras. */ + void launchChooseLock(@Nullable Bundle chooseLockFingerprintExtras); + } + + private final int mCurrentUserId; + private final PackageManager mPackageManager; + @Nullable private final FingerprintManager mFingerprintManager; + private final DevicePolicyManager mDevicePolicyManager; + private final Ui mUi; + + public SetNewPasswordController(Context context, Ui ui) { + this(context.getUserId(), + context.getPackageManager(), + (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE), + (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE), + ui); + } + + @VisibleForTesting + SetNewPasswordController( + int currentUserId, + PackageManager packageManager, + FingerprintManager fingerprintManager, + DevicePolicyManager devicePolicyManager, + Ui ui) { + mCurrentUserId = currentUserId; + mPackageManager = checkNotNull(packageManager); + mFingerprintManager = fingerprintManager; + mDevicePolicyManager = checkNotNull(devicePolicyManager); + mUi = checkNotNull(ui); + } + + /** + * Dispatches the set new password intent to the correct activity that handles it. + */ + public void dispatchSetNewPasswordIntent() { + if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT) + && mFingerprintManager != null + && mFingerprintManager.isHardwareDetected() + && !mFingerprintManager.hasEnrolledFingerprints() + && !isFingerprintDisabledByAdmin()) { + mUi.launchChooseLock(getFingerprintChooseLockExtras()); + } else { + mUi.launchChooseLock(null); + } + } + + private Bundle getFingerprintChooseLockExtras() { + Bundle chooseLockExtras = new Bundle(); + if (mFingerprintManager != null) { + long challenge = mFingerprintManager.preEnroll(); + chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, + DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + chooseLockExtras.putBoolean( + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true); + chooseLockExtras.putLong(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); + chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true); + if (mCurrentUserId != UserHandle.USER_NULL) { + chooseLockExtras.putInt(Intent.EXTRA_USER_ID, mCurrentUserId); + } + } + return chooseLockExtras; + } + + private boolean isFingerprintDisabledByAdmin() { + int disabledFeatures = mDevicePolicyManager.getKeyguardDisabledFeatures( + null, mCurrentUserId); + return (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0; + } +} diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java new file mode 100644 index 00000000000..61dbe08dc0b --- /dev/null +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.password; + +import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; +import static com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS; +import static com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY; +import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE; +import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT; +import static com.android.settings.ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.fingerprint.FingerprintManager; +import android.os.Bundle; + +import com.android.settings.TestConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +/** + * Tests for {@link SetNewPasswordController}. + */ +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public final class SetNewPasswordControllerTest { + private static final int CURRENT_UID = 101; + private static final long FINGERPRINT_CHALLENGE = -9876512313131L; + + @Mock PackageManager mPackageManager; + @Mock FingerprintManager mFingerprintManager; + @Mock DevicePolicyManager mDevicePolicyManager; + + @Mock private SetNewPasswordController.Ui mUi; + private SetNewPasswordController mSetNewPasswordController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mSetNewPasswordController = new SetNewPasswordController( + CURRENT_UID, mPackageManager, mFingerprintManager, mDevicePolicyManager, mUi); + + when(mFingerprintManager.preEnroll()).thenReturn(FINGERPRINT_CHALLENGE); + when(mPackageManager.hasSystemFeature(eq(FEATURE_FINGERPRINT))).thenReturn(true); + } + + @Test + public void launchChooseLockWithFingerprint() { + // GIVEN the device supports fingerprint. + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + // GIVEN there are no enrolled fingerprints. + when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(false); + // GIVEN DPC does not disallow fingerprint for keyguard usage. + when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) + .thenReturn(0); + + // WHEN the controller dispatches a set new password intent. + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + + // THEN the choose lock activity is launched with fingerprint extras. + ArgumentCaptor bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class); + verify(mUi).launchChooseLock(bundleArgumentCaptor.capture()); + // THEN the extras have all values for fingerprint setup. + compareFingerprintExtras(bundleArgumentCaptor.getValue()); + } + + @Test + public void launchChooseLockWithoutFingerprint_noFingerprintFeature() { + // GIVEN the device does NOT support fingerprint feature. + when(mPackageManager.hasSystemFeature(eq(FEATURE_FINGERPRINT))).thenReturn(false); + + // WHEN the controller dispatches a set new password intent. + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + + // THEN the choose lock activity is launched without fingerprint extras. + verify(mUi).launchChooseLock(null); + } + + @Test + public void launchChooseLockWithoutFingerprint_noFingerprintSensor() { + // GIVEN the device does NOT support fingerprint. + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + // GIVEN there are no enrolled fingerprints. + when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(false); + // GIVEN DPC does not disallow fingerprint for keyguard usage. + when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) + .thenReturn(0); + + // WHEN the controller dispatches a set new password intent. + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + + // THEN the choose lock activity is launched without fingerprint extras. + verify(mUi).launchChooseLock(null); + } + + @Test + public void launchChooseLockWithoutFingerprint_hasFingerprintEnrolled() { + // GIVEN the device supports fingerprint. + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + // GIVEN there are no enrolled fingerprints. + when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true); + // GIVEN DPC does not disallow fingerprint for keyguard usage. + when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) + .thenReturn(0); + + // WHEN the controller dispatches a set new password intent. + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + + // THEN the choose lock activity is launched without fingerprint extras. + verify(mUi).launchChooseLock(null); + } + + @Test + public void launchChooseLockWithoutFingerprint_deviceAdminDisallowFingerprintForKeyguard() { + // GIVEN the device supports fingerprint. + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); + // GIVEN there is an enrolled fingerprint. + when(mFingerprintManager.hasEnrolledFingerprints()).thenReturn(true); + // GIVEN DPC disallows fingerprint for keyguard usage. + when(mDevicePolicyManager.getKeyguardDisabledFeatures(any(ComponentName.class))) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + + // WHEN the controller dispatches a set new password intent. + mSetNewPasswordController.dispatchSetNewPasswordIntent(); + + // THEN the choose lock activity is launched without fingerprint extras. + verify(mUi).launchChooseLock(null); + } + + private void compareFingerprintExtras(Bundle actualBundle) { + assertEquals( + "Password quality must be something in order to config fingerprint.", + DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, + actualBundle.getInt(MINIMUM_QUALITY_KEY)); + assertTrue( + "All disabled preference should be removed.", + actualBundle.getBoolean(HIDE_DISABLED_PREFS)); + assertTrue( + "There must be a fingerprint challenge.", + actualBundle.getBoolean(EXTRA_KEY_HAS_CHALLENGE)); + assertEquals( + "The fingerprint challenge must come from the FingerprintManager", + FINGERPRINT_CHALLENGE, + actualBundle.getLong(EXTRA_KEY_CHALLENGE)); + assertTrue( + "The request must be a fingerprint set up request.", + actualBundle.getBoolean(EXTRA_KEY_FOR_FINGERPRINT)); + assertEquals( + "User id must be equaled to the input one.", + CURRENT_UID, + actualBundle.getInt(Intent.EXTRA_USER_ID)); + } +}