2/n: Add default implementation for multi-biometric enroll
1) Adds a layout for multi-biometric selection in BiometricEnrollActivity 2) Adds widgets for checkboxes 3) Shows ConfirmLock*/ChooseLock* for multi-biometric devices in BiometricEnrollActivity 4) finish()'s when loses foreground 5) Adds default string for ChooseLock* and multi-biometrics, e.g. "Set up Password + Biometrics", as well as associated plumbing to bring the user back to BiometricEnrollActivity once the credential is enrolled 6) When max templates enrolled, checkbox becomes disabled and description string is updated Bug: 162341940 Bug: 152242790 Fixes: 161742393 No effect on existing devices with the following: Test: adb shell am start -a android.settings.BIOMETRIC_ENROLL Test: SUW Test: make -j RunSettingsRoboTests Exempt-From-Owner-Approval: Biometric-related change to EncryptionInterstitial Change-Id: I855460d50228ace24d4ec5fbe330f02ab406cc02
This commit is contained in:
@@ -111,6 +111,8 @@ public class EncryptionInterstitial extends SettingsActivity {
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
final boolean forFace = getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
final boolean forBiometrics = getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
Intent intent = getActivity().getIntent();
|
||||
mRequestedPasswordQuality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
|
||||
mUnlockMethodIntent = intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT);
|
||||
@@ -121,6 +123,8 @@ public class EncryptionInterstitial extends SettingsActivity {
|
||||
R.string.encryption_interstitial_message_pattern_for_fingerprint :
|
||||
forFace ?
|
||||
R.string.encryption_interstitial_message_pattern_for_face :
|
||||
forBiometrics ?
|
||||
R.string.encryption_interstitial_message_pattern_for_biometrics :
|
||||
R.string.encryption_interstitial_message_pattern;
|
||||
break;
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
||||
@@ -129,6 +133,8 @@ public class EncryptionInterstitial extends SettingsActivity {
|
||||
R.string.encryption_interstitial_message_pin_for_fingerprint :
|
||||
forFace ?
|
||||
R.string.encryption_interstitial_message_pin_for_face :
|
||||
forBiometrics ?
|
||||
R.string.encryption_interstitial_message_pin_for_biometrics :
|
||||
R.string.encryption_interstitial_message_pin;
|
||||
break;
|
||||
default:
|
||||
@@ -136,6 +142,8 @@ public class EncryptionInterstitial extends SettingsActivity {
|
||||
R.string.encryption_interstitial_message_password_for_fingerprint :
|
||||
forFace ?
|
||||
R.string.encryption_interstitial_message_password_for_face :
|
||||
forBiometrics ?
|
||||
R.string.encryption_interstitial_message_password_for_biometrics :
|
||||
R.string.encryption_interstitial_message_password;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,23 +21,36 @@ import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.hardware.biometrics.BiometricManager.Authenticators;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorProperties;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
|
||||
import com.android.settings.core.InstrumentedActivity;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockPattern;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* Trampoline activity launched by the {@code android.settings.BIOMETRIC_ENROLL} action which
|
||||
@@ -49,18 +62,53 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
|
||||
private static final String TAG = "BiometricEnrollActivity";
|
||||
|
||||
private static final int REQUEST_CHOOSE_LOCK = 1;
|
||||
private static final int REQUEST_CONFIRM_LOCK = 2;
|
||||
|
||||
public static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP;
|
||||
|
||||
// Intent extra. If true, biometric enrollment should skip introductory screens. Currently
|
||||
// this only applies to fingerprint.
|
||||
public static final String EXTRA_SKIP_INTRO = "skip_intro";
|
||||
|
||||
private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
|
||||
private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle";
|
||||
|
||||
public static final class InternalActivity extends BiometricEnrollActivity {}
|
||||
|
||||
private int mUserId = UserHandle.myUserId();
|
||||
private boolean mConfirmingCredentials;
|
||||
@Nullable private Long mGkPwHandle;
|
||||
private BiometricEnrollCheckbox mCheckboxFace;
|
||||
private BiometricEnrollCheckbox mCheckboxFingerprint;
|
||||
@Nullable private MultiBiometricEnrollHelper mMultiBiometricEnrollHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (this instanceof InternalActivity) {
|
||||
mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mConfirmingCredentials = savedInstanceState
|
||||
.getBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, false);
|
||||
if (savedInstanceState.containsKey(SAVED_STATE_GK_PW_HANDLE)) {
|
||||
mGkPwHandle = savedInstanceState.getLong(SAVED_STATE_GK_PW_HANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Put the theme in the intent so it gets propagated to other activities in the flow
|
||||
final Intent intent = getIntent();
|
||||
if (intent.getStringExtra(WizardManagerHelper.EXTRA_THEME) == null) {
|
||||
intent.putExtra(
|
||||
WizardManagerHelper.EXTRA_THEME,
|
||||
SetupWizardUtils.getThemeString(intent));
|
||||
}
|
||||
|
||||
// Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
|
||||
final int authenticators = getIntent().getIntExtra(
|
||||
final int authenticators = intent.getIntExtra(
|
||||
Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
|
||||
|
||||
Log.d(TAG, "Authenticators: " + authenticators);
|
||||
@@ -73,9 +121,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
|
||||
if (isSetupWizard) {
|
||||
if (hasFeatureFace && hasFeatureFingerprint) {
|
||||
// TODO(b/162341940, b/152242790) this should show a multi-biometric selection
|
||||
// screen
|
||||
launchFingerprintOnlyEnroll();
|
||||
setupForMultiBiometricEnroll();
|
||||
} else if (hasFeatureFace) {
|
||||
launchFaceOnlyEnroll();
|
||||
} else if (hasFeatureFingerprint) {
|
||||
@@ -98,9 +144,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
if (authenticators == BiometricManager.Authenticators.DEVICE_CREDENTIAL) {
|
||||
launchCredentialOnlyEnroll();
|
||||
} else if (hasFeatureFace && hasFeatureFingerprint) {
|
||||
// TODO(b/162341940, b/152242790) this should show a multi-biometric selection
|
||||
// screen
|
||||
launchFingerprintOnlyEnroll();
|
||||
setupForMultiBiometricEnroll();
|
||||
} else if (hasFeatureFingerprint) {
|
||||
launchFingerprintOnlyEnroll();
|
||||
} else if (hasFeatureFace) {
|
||||
@@ -112,30 +156,216 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
|
||||
if (mGkPwHandle != null) {
|
||||
outState.putLong(SAVED_STATE_GK_PW_HANDLE, mGkPwHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (mMultiBiometricEnrollHelper == null) {
|
||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||
|
||||
switch (requestCode) {
|
||||
case REQUEST_CHOOSE_LOCK:
|
||||
mConfirmingCredentials = false;
|
||||
if (resultCode == ChooseLockPattern.RESULT_FINISHED) {
|
||||
mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
|
||||
} else {
|
||||
Log.d(TAG, "Unknown result for chooseLock: " + resultCode);
|
||||
setResult(resultCode);
|
||||
finish();
|
||||
}
|
||||
break;
|
||||
case REQUEST_CONFIRM_LOCK:
|
||||
mConfirmingCredentials = false;
|
||||
if (resultCode == RESULT_OK) {
|
||||
mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
|
||||
} else {
|
||||
Log.d(TAG, "Unknown result for confirmLock: " + resultCode);
|
||||
finish();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown requestCode: " + requestCode + ", finishing");
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
mMultiBiometricEnrollHelper.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
|
||||
resid = SetupWizardUtils.getTheme(getIntent());
|
||||
theme.applyStyle(R.style.SetupWizardPartnerResource, true);
|
||||
super.onApplyThemeResource(theme, resid, first);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
if (mConfirmingCredentials || mMultiBiometricEnrollHelper != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChangingConfigurations()) {
|
||||
Log.d(TAG, "Finishing in onStop");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupForMultiBiometricEnroll() {
|
||||
setContentView(R.layout.biometric_enroll_layout);
|
||||
|
||||
mCheckboxFace = findViewById(R.id.checkbox_face);
|
||||
mCheckboxFingerprint = findViewById(R.id.checkbox_fingerprint);
|
||||
|
||||
mCheckboxFace.setListener(this::updateNextButton);
|
||||
mCheckboxFingerprint.setListener(this::updateNextButton);
|
||||
|
||||
final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
|
||||
final FaceManager faceManager = getSystemService(FaceManager.class);
|
||||
final List<FingerprintSensorProperties> fpProperties =
|
||||
fingerprintManager.getSensorProperties();
|
||||
final List<FaceSensorProperties> faceProperties = faceManager.getSensorProperties();
|
||||
|
||||
// This would need to be updated for devices with multiple sensors of the same modality
|
||||
final boolean maxFacesEnrolled = faceManager.getEnrolledFaces(mUserId).size()
|
||||
>= faceProperties.get(0).maxTemplatesAllowed;
|
||||
final boolean maxFingerprintsEnrolled = fingerprintManager.getEnrolledFingerprints(mUserId)
|
||||
.size() >= fpProperties.get(0).maxTemplatesAllowed;
|
||||
|
||||
if (maxFacesEnrolled) {
|
||||
mCheckboxFace.setEnabled(false);
|
||||
mCheckboxFace.setDescription(R.string.face_intro_error_max);
|
||||
}
|
||||
|
||||
if (maxFingerprintsEnrolled) {
|
||||
mCheckboxFingerprint.setEnabled(false);
|
||||
mCheckboxFingerprint.setDescription(R.string.fingerprint_intro_error_max);
|
||||
}
|
||||
|
||||
final FooterBarMixin footerBarMixin = ((GlifLayout) findViewById(R.id.setup_wizard_layout))
|
||||
.getMixin(FooterBarMixin.class);
|
||||
footerBarMixin.setSecondaryButton(new FooterButton.Builder(this)
|
||||
.setText(R.string.multi_biometric_enroll_skip)
|
||||
.setListener(this::onButtonNegative)
|
||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||
.setTheme(R.style.SudGlifButton_Secondary)
|
||||
.build());
|
||||
|
||||
footerBarMixin.setPrimaryButton(new FooterButton.Builder(this)
|
||||
.setText(R.string.multi_biometric_enroll_next)
|
||||
.setListener(this::onButtonPositive)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build());
|
||||
|
||||
footerBarMixin.getSecondaryButton().setVisibility(View.VISIBLE);
|
||||
footerBarMixin.getPrimaryButton().setVisibility(View.VISIBLE);
|
||||
|
||||
if (!mConfirmingCredentials && mGkPwHandle == null) {
|
||||
mConfirmingCredentials = true;
|
||||
if (!userHasPassword(mUserId)) {
|
||||
launchChooseLock();
|
||||
} else {
|
||||
launchConfirmLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNextButton(View view) {
|
||||
final boolean canEnrollAny = canEnrollFace() || canEnrollFingerprint();
|
||||
|
||||
final FooterBarMixin footerBarMixin = ((GlifLayout) findViewById(R.id.setup_wizard_layout))
|
||||
.getMixin(FooterBarMixin.class);
|
||||
footerBarMixin.getPrimaryButton().setEnabled(canEnrollAny);
|
||||
}
|
||||
|
||||
private void onButtonPositive(View view) {
|
||||
// Start the state machine according to checkboxes, taking max enrolled into account
|
||||
mMultiBiometricEnrollHelper = new MultiBiometricEnrollHelper(this, mUserId,
|
||||
canEnrollFace(), canEnrollFingerprint(), mGkPwHandle);
|
||||
mMultiBiometricEnrollHelper.startNextStep();
|
||||
}
|
||||
|
||||
private void onButtonNegative(View view) {
|
||||
setResult(RESULT_SKIP);
|
||||
finish();
|
||||
}
|
||||
|
||||
private boolean canEnrollFace() {
|
||||
return mCheckboxFace.isEnabled() && mCheckboxFace.isChecked();
|
||||
}
|
||||
|
||||
private boolean canEnrollFingerprint() {
|
||||
return mCheckboxFingerprint.isEnabled() && mCheckboxFingerprint.isChecked();
|
||||
}
|
||||
|
||||
private boolean userHasPassword(int userId) {
|
||||
final UserManager userManager = getSystemService(UserManager.class);
|
||||
final int passwordQuality = new LockPatternUtils(this)
|
||||
.getActivePasswordQuality(userManager.getCredentialOwnerProfile(userId));
|
||||
return passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||
}
|
||||
|
||||
private void launchChooseLock() {
|
||||
Log.d(TAG, "launchChooseLock");
|
||||
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
||||
|
||||
if (mUserId != UserHandle.USER_NULL) {
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||
}
|
||||
startActivityForResult(intent, REQUEST_CHOOSE_LOCK);
|
||||
}
|
||||
|
||||
private void launchConfirmLock() {
|
||||
Log.d(TAG, "launchConfirmLock");
|
||||
final ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this);
|
||||
builder.setRequestCode(REQUEST_CONFIRM_LOCK)
|
||||
.setRequestGatekeeperPasswordHandle(true)
|
||||
.setForegroundOnly(true)
|
||||
.setReturnCredentials(true);
|
||||
if (mUserId != UserHandle.USER_NULL) {
|
||||
builder.setUserId(mUserId);
|
||||
}
|
||||
final boolean launched = builder.show();
|
||||
if (!launched) {
|
||||
// This shouldn't happen, as we should only end up at this step if a lock thingy is
|
||||
// already set.
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be used to launch enrollment for single-sensor devices, which use
|
||||
* FLAG_ACTIVITY_FORWARD_RESULT path.
|
||||
*
|
||||
* @param intent Enrollment activity that should be started (e.g. FaceEnrollIntroduction.class,
|
||||
* etc).
|
||||
*/
|
||||
private void launchEnrollActivity(@NonNull Intent intent) {
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||
byte[] hardwareAuthToken = null;
|
||||
if (this instanceof InternalActivity) {
|
||||
// Propagate challenge and user Id from ChooseLockGeneric.
|
||||
final byte[] token = getIntent()
|
||||
.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
final int userId = getIntent()
|
||||
.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
|
||||
final long gkPwHandle = getIntent().getLongExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L);
|
||||
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
||||
if (gkPwHandle != 0L) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
}
|
||||
hardwareAuthToken = getIntent().getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
}
|
||||
|
||||
startActivity(intent);
|
||||
finish();
|
||||
BiometricUtils.launchEnrollForResult(this, intent, 0 /* requestCode */, hardwareAuthToken,
|
||||
null /* gkPwHandle */, mUserId);
|
||||
}
|
||||
|
||||
private void launchCredentialOnlyEnroll() {
|
||||
@@ -152,40 +382,18 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
||||
// ChooseLockGeneric can request to start fingerprint enroll bypassing the intro screen.
|
||||
if (getIntent().getBooleanExtra(EXTRA_SKIP_INTRO, false)
|
||||
&& this instanceof InternalActivity) {
|
||||
intent = getFingerprintFindSensorIntent();
|
||||
intent = BiometricUtils.getFingerprintFindSensorIntent(this, getIntent());
|
||||
} else {
|
||||
intent = getFingerprintIntroIntent();
|
||||
intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
|
||||
}
|
||||
launchEnrollActivity(intent);
|
||||
}
|
||||
|
||||
private void launchFaceOnlyEnroll() {
|
||||
final Intent intent = getFaceIntroIntent();
|
||||
final Intent intent = BiometricUtils.getFaceIntroIntent(this, getIntent());
|
||||
launchEnrollActivity(intent);
|
||||
}
|
||||
|
||||
private Intent getFingerprintFindSensorIntent() {
|
||||
Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
|
||||
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private Intent getFingerprintIntroIntent() {
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
Intent intent = new Intent(this, SetupFingerprintEnrollIntroduction.class);
|
||||
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
|
||||
return intent;
|
||||
} else {
|
||||
return new Intent(this, FingerprintEnrollIntroduction.class);
|
||||
}
|
||||
}
|
||||
|
||||
private Intent getFaceIntroIntent() {
|
||||
Intent intent = new Intent(this, FaceEnrollIntroduction.class);
|
||||
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.BIOMETRIC_ENROLL_ACTIVITY;
|
||||
|
||||
@@ -57,6 +57,9 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
* starting the next activity. However, this leads to broken 'Back'
|
||||
* behavior. So, now an activity does not finish itself until it gets this
|
||||
* result.
|
||||
*
|
||||
* This must be the same as
|
||||
* {@link com.android.settings.password.ChooseLockPattern#RESULT_FINISHED}
|
||||
*/
|
||||
public static final int RESULT_FINISHED = RESULT_FIRST_USER;
|
||||
|
||||
@@ -78,6 +81,11 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
public static final int LEARN_MORE_REQUEST = 3;
|
||||
public static final int CONFIRM_REQUEST = 4;
|
||||
public static final int ENROLL_REQUEST = 5;
|
||||
/**
|
||||
* Request code when starting another biometric enrollment from within a biometric flow. For
|
||||
* example, when starting fingerprint enroll after face enroll.
|
||||
*/
|
||||
public static final int ENROLL_NEXT_BIOMETRIC_REQUEST = 6;
|
||||
|
||||
protected boolean mLaunchedConfirmLock;
|
||||
protected byte[] mToken;
|
||||
|
||||
115
src/com/android/settings/biometrics/BiometricEnrollCheckbox.java
Normal file
115
src/com/android/settings/biometrics/BiometricEnrollCheckbox.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.biometrics;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Widget contain space for an icon, title, description, and checkbox. On devices with multiple
|
||||
* biometric sensors, allows users to choose sensors during {@link BiometricEnrollActivity}.
|
||||
*/
|
||||
public class BiometricEnrollCheckbox extends LinearLayout {
|
||||
|
||||
@NonNull private final CheckBox mCheckBox;
|
||||
@NonNull private final TextView mDescriptionView;
|
||||
@Nullable private View.OnClickListener mListener;
|
||||
|
||||
public BiometricEnrollCheckbox(Context context) {
|
||||
this(context, null /* attrs */);
|
||||
}
|
||||
|
||||
public BiometricEnrollCheckbox(Context context,
|
||||
@Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0 /* defStyleAttr */);
|
||||
}
|
||||
|
||||
public BiometricEnrollCheckbox(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
|
||||
}
|
||||
|
||||
public BiometricEnrollCheckbox(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
|
||||
LayoutInflater.from(context).inflate(R.layout.biometric_enroll_checkbox,
|
||||
this, true /* attachToRoot */);
|
||||
|
||||
mCheckBox = findViewById(R.id.checkbox);
|
||||
final ImageView iconView = findViewById(R.id.icon);
|
||||
final TextView titleView = findViewById(R.id.title);
|
||||
mDescriptionView = findViewById(R.id.description);
|
||||
|
||||
setOnClickListener(view -> {
|
||||
if (isEnabled()) {
|
||||
mCheckBox.toggle();
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onClick(view);
|
||||
}
|
||||
});
|
||||
|
||||
final TypedArray a = context
|
||||
.obtainStyledAttributes(attrs, R.styleable.BiometricEnrollCheckbox);
|
||||
try {
|
||||
final Drawable icon =
|
||||
a.getDrawable(R.styleable.BiometricEnrollCheckbox_icon);
|
||||
final CharSequence title =
|
||||
a.getText(R.styleable.BiometricEnrollCheckbox_title);
|
||||
final CharSequence description =
|
||||
a.getText(R.styleable.BiometricEnrollCheckbox_description);
|
||||
iconView.setImageDrawable(icon);
|
||||
titleView.setText(title);
|
||||
mDescriptionView.setText(description);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener(View.OnClickListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mCheckBox.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return mCheckBox.isChecked();
|
||||
}
|
||||
|
||||
public void setDescription(@StringRes int resId) {
|
||||
mDescriptionView.setText(resId);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -29,9 +29,7 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.SetupChooseLockGeneric;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
@@ -43,6 +41,8 @@ import com.google.android.setupdesign.span.LinkSpan;
|
||||
public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
implements LinkSpan.OnClickListener {
|
||||
|
||||
private static final String TAG = "BiometricEnrollIntroduction";
|
||||
|
||||
private static final String KEY_CONFIRMING_CREDENTIALS = "confirming_credentials";
|
||||
|
||||
private UserManager mUserManager;
|
||||
@@ -164,7 +164,8 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
// No password registered, launch into enrollment wizard.
|
||||
mConfirmingCredentials = true;
|
||||
launchChooseLock();
|
||||
} else if (!BiometricUtils.containsGatekeeperPassword(getIntent()) && mToken == null) {
|
||||
} else if (!BiometricUtils.containsGatekeeperPasswordHandle(getIntent())
|
||||
&& mToken == null) {
|
||||
// It's possible to have a token but mLaunchedConfirmLock == false, since
|
||||
// ChooseLockGeneric can pass us a token.
|
||||
mConfirmingCredentials = true;
|
||||
@@ -220,7 +221,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
}
|
||||
|
||||
private void launchChooseLock() {
|
||||
Intent intent = getChooseLockIntent();
|
||||
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
||||
@@ -240,27 +241,11 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
if (mUserId != UserHandle.USER_NULL) {
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||
}
|
||||
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
|
||||
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
|
||||
startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST);
|
||||
}
|
||||
|
||||
protected Intent getChooseLockIntent() {
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
// Default to PIN lock in setup wizard
|
||||
Intent intent = new Intent(this, SetupChooseLockGeneric.class);
|
||||
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
|
||||
intent.putExtra(
|
||||
LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
intent.putExtra(ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, true);
|
||||
}
|
||||
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
|
||||
return intent;
|
||||
} else {
|
||||
return new Intent(this, ChooseLockGeneric.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
|
||||
@@ -301,6 +286,12 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
}
|
||||
} else if (requestCode == LEARN_MORE_REQUEST) {
|
||||
overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out);
|
||||
} else if (requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST) {
|
||||
Log.d(TAG, "ENROLL_NEXT_BIOMETRIC_REQUEST, result: " + resultCode);
|
||||
if (resultCode != RESULT_CANCELED) {
|
||||
setResult(resultCode, data);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@@ -16,16 +16,35 @@
|
||||
|
||||
package com.android.settings.biometrics;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.SetupChooseLockGeneric;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
/**
|
||||
* Common biometric utilities.
|
||||
*/
|
||||
public class BiometricUtils {
|
||||
private static final String TAG = "BiometricUtils";
|
||||
/**
|
||||
* Given the result from confirming or choosing a credential, request Gatekeeper to generate
|
||||
* a HardwareAuthToken with the Gatekeeper Password together with a biometric challenge.
|
||||
@@ -36,24 +55,29 @@ public class BiometricUtils {
|
||||
* @param challenge Unique biometric challenge from FingerprintManager/FaceManager
|
||||
* @return
|
||||
*/
|
||||
public static byte[] requestGatekeeperHat(Context context, Intent result, int userId,
|
||||
long challenge) {
|
||||
final long gatekeeperPasswordHandle = result.getLongExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L);
|
||||
if (gatekeeperPasswordHandle == 0L) {
|
||||
public static byte[] requestGatekeeperHat(@NonNull Context context, @NonNull Intent result,
|
||||
int userId, long challenge) {
|
||||
if (!containsGatekeeperPasswordHandle(result)) {
|
||||
throw new IllegalStateException("Gatekeeper Password is missing!!");
|
||||
}
|
||||
final long gatekeeperPasswordHandle = result.getLongExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L);
|
||||
return requestGatekeeperHat(context, gatekeeperPasswordHandle, userId, challenge);
|
||||
}
|
||||
|
||||
public static byte[] requestGatekeeperHat(@NonNull Context context, long gkPwHandle, int userId,
|
||||
long challenge) {
|
||||
final LockPatternUtils utils = new LockPatternUtils(context);
|
||||
return utils.verifyGatekeeperPasswordHandle(gatekeeperPasswordHandle, challenge, userId)
|
||||
return utils.verifyGatekeeperPasswordHandle(gkPwHandle, challenge, userId)
|
||||
.getGatekeeperHAT();
|
||||
}
|
||||
|
||||
public static boolean containsGatekeeperPassword(Intent data) {
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
return data.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L) != 0L;
|
||||
public static boolean containsGatekeeperPasswordHandle(@Nullable Intent data) {
|
||||
return data != null && data.hasExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE);
|
||||
}
|
||||
|
||||
public static long getGatekeeperPasswordHandle(@NonNull Intent data) {
|
||||
return data.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,16 +88,157 @@ public class BiometricUtils {
|
||||
* @param context Caller's context
|
||||
* @param data The onActivityResult intent from ChooseLock* or ConfirmLock*
|
||||
*/
|
||||
public static void removeGatekeeperPasswordHandle(Context context, Intent data) {
|
||||
public static void removeGatekeeperPasswordHandle(@NonNull Context context,
|
||||
@Nullable Intent data) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
final long gatekeeperPasswordsHandle = data.getLongExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 0L);
|
||||
if (gatekeeperPasswordsHandle == 0L) {
|
||||
if (!containsGatekeeperPasswordHandle(data)) {
|
||||
return;
|
||||
}
|
||||
removeGatekeeperPasswordHandle(context, getGatekeeperPasswordHandle(data));
|
||||
}
|
||||
|
||||
public static void removeGatekeeperPasswordHandle(@NonNull Context context, long handle) {
|
||||
final LockPatternUtils utils = new LockPatternUtils(context);
|
||||
utils.removeGatekeeperPasswordHandle(gatekeeperPasswordsHandle);
|
||||
utils.removeGatekeeperPasswordHandle(handle);
|
||||
Log.d(TAG, "Removed handle");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context caller's context
|
||||
* @param activityIntent The intent that started the caller's activity
|
||||
* @return Intent for starting ChooseLock*
|
||||
*/
|
||||
public static Intent getChooseLockIntent(@NonNull Context context,
|
||||
@NonNull Intent activityIntent) {
|
||||
if (WizardManagerHelper.isAnySetupWizard(activityIntent)) {
|
||||
// Default to PIN lock in setup wizard
|
||||
Intent intent = new Intent(context, SetupChooseLockGeneric.class);
|
||||
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
|
||||
intent.putExtra(
|
||||
LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment
|
||||
.EXTRA_SHOW_OPTIONS_BUTTON, true);
|
||||
}
|
||||
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
||||
return intent;
|
||||
} else {
|
||||
return new Intent(context, ChooseLockGeneric.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context caller's context
|
||||
* @param activityIntent The intent that started the caller's activity
|
||||
* @return Intent for starting FingerprintEnrollFindSensor
|
||||
*/
|
||||
public static Intent getFingerprintFindSensorIntent(@NonNull Context context,
|
||||
@NonNull Intent activityIntent) {
|
||||
Intent intent = new Intent(context, FingerprintEnrollFindSensor.class);
|
||||
SetupWizardUtils.copySetupExtras(activityIntent, intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context caller's context
|
||||
* @param activityIntent The intent that started the caller's activity
|
||||
* @return Intent for starting FingerprintEnrollIntroduction
|
||||
*/
|
||||
public static Intent getFingerprintIntroIntent(@NonNull Context context,
|
||||
@NonNull Intent activityIntent) {
|
||||
if (WizardManagerHelper.isAnySetupWizard(activityIntent)) {
|
||||
Intent intent = new Intent(context, SetupFingerprintEnrollIntroduction.class);
|
||||
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
||||
return intent;
|
||||
} else {
|
||||
return new Intent(context, FingerprintEnrollIntroduction.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context caller's context
|
||||
* @param activityIntent The intent that started the caller's activity
|
||||
* @return Intent for starting FaceEnrollIntroduction
|
||||
*/
|
||||
public static Intent getFaceIntroIntent(@NonNull Context context,
|
||||
@NonNull Intent activityIntent) {
|
||||
Intent intent = new Intent(context, FaceEnrollIntroduction.class);
|
||||
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param activity Reference to the calling activity, used to startActivity
|
||||
* @param intent Intent pointing to the enrollment activity
|
||||
* @param requestCode If non-zero, will invoke startActivityForResult instead of startActivity
|
||||
* @param hardwareAuthToken HardwareAuthToken from Gatekeeper
|
||||
* @param userId User to request enrollment for
|
||||
*/
|
||||
public static void launchEnrollForResult(@NonNull BiometricEnrollActivity activity,
|
||||
@NonNull Intent intent, int requestCode,
|
||||
@Nullable byte[] hardwareAuthToken, @Nullable Long gkPwHandle, int userId) {
|
||||
if (hardwareAuthToken != null) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
|
||||
hardwareAuthToken);
|
||||
}
|
||||
if (gkPwHandle != null) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
}
|
||||
|
||||
if (activity instanceof BiometricEnrollActivity.InternalActivity) {
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
||||
}
|
||||
|
||||
if (requestCode != 0) {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
} else {
|
||||
activity.startActivity(intent);
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param activity Activity that we want to check
|
||||
* @return True if the activity is going through a multi-biometric enrollment flow.
|
||||
*/
|
||||
public static boolean isMultiBiometricEnrollmentFlow(@NonNull Activity activity) {
|
||||
return activity.getIntent().hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE);
|
||||
}
|
||||
|
||||
public static void copyMultiBiometricExtras(@NonNull Intent fromIntent,
|
||||
@NonNull Intent toIntent) {
|
||||
final PendingIntent pendingIntent = (PendingIntent) fromIntent.getExtra(
|
||||
MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, null);
|
||||
if (pendingIntent != null) {
|
||||
toIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current biometric enrollment (e.g. face) should be followed by another one (e.g.
|
||||
* fingerprint) (see {@link #isMultiBiometricEnrollmentFlow(Activity)}), retrieves the
|
||||
* PendingIntent pointing to the next enrollment and starts it. The caller will receive the
|
||||
* result in onActivityResult.
|
||||
* @return true if the next enrollment was started
|
||||
*/
|
||||
public static boolean tryStartingNextBiometricEnroll(@NonNull Activity activity,
|
||||
int requestCode) {
|
||||
final PendingIntent pendingIntent = (PendingIntent) activity.getIntent()
|
||||
.getExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE);
|
||||
if (pendingIntent != null) {
|
||||
try {
|
||||
Log.d(TAG, "Starting pendingIntent: " + pendingIntent);
|
||||
IntentSender intentSender = pendingIntent.getIntentSender();
|
||||
activity.startIntentSenderForResult(intentSender, requestCode,
|
||||
null /* fillInIntent */, 0 /* flagMask */, 0 /* flagValues */,
|
||||
0 /* extraFlags */);
|
||||
return true;
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.e(TAG, "Pending intent canceled: " + e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.biometrics;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
|
||||
/**
|
||||
* Helper for {@link BiometricEnrollActivity} when multiple sensors exist on a device.
|
||||
*/
|
||||
public class MultiBiometricEnrollHelper {
|
||||
|
||||
private static final String TAG = "MultiBiometricEnrollHelper";
|
||||
|
||||
private static final int REQUEST_FACE_ENROLL = 3000;
|
||||
private static final int REQUEST_FINGERPRINT_ENROLL = 3001;
|
||||
|
||||
public static final String EXTRA_ENROLL_AFTER_FACE = "enroll_after_face";
|
||||
|
||||
@NonNull private final BiometricEnrollActivity mActivity;
|
||||
private final long mGkPwHandle;
|
||||
private final int mUserId;
|
||||
private final boolean mRequestEnrollFace;
|
||||
private final boolean mRequestEnrollFingerprint;
|
||||
|
||||
MultiBiometricEnrollHelper(@NonNull BiometricEnrollActivity activity, int userId,
|
||||
boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) {
|
||||
mActivity = activity;
|
||||
mUserId = userId;
|
||||
mGkPwHandle = gkPwHandle;
|
||||
mRequestEnrollFace = enrollFace;
|
||||
mRequestEnrollFingerprint = enrollFingerprint;
|
||||
}
|
||||
|
||||
void startNextStep() {
|
||||
if (mRequestEnrollFace) {
|
||||
launchFaceEnroll();
|
||||
} else if (mRequestEnrollFingerprint) {
|
||||
launchFingerprintEnroll();
|
||||
} else {
|
||||
mActivity.setResult(BiometricEnrollIntroduction.RESULT_SKIP);
|
||||
mActivity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void launchFaceEnroll() {
|
||||
final FaceManager faceManager = mActivity.getSystemService(FaceManager.class);
|
||||
faceManager.generateChallenge((sensorId, challenge) -> {
|
||||
final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
|
||||
mGkPwHandle, mUserId, challenge);
|
||||
final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
|
||||
mActivity.getIntent());
|
||||
|
||||
if (mRequestEnrollFingerprint) {
|
||||
// Give FaceEnroll a pendingIntent pointing to fingerprint enrollment, so that it
|
||||
// can be started when user skips or finishes face enrollment.
|
||||
final Intent fpIntent = BiometricUtils.getFingerprintIntroIntent(mActivity,
|
||||
mActivity.getIntent());
|
||||
fpIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
|
||||
final PendingIntent fpAfterFaceIntent = PendingIntent.getActivity(mActivity,
|
||||
0 /* requestCode */, fpIntent, 0 /* flags */);
|
||||
faceIntent.putExtra(EXTRA_ENROLL_AFTER_FACE, fpAfterFaceIntent);
|
||||
}
|
||||
|
||||
BiometricUtils.launchEnrollForResult(mActivity, faceIntent, REQUEST_FACE_ENROLL,
|
||||
hardwareAuthToken, mGkPwHandle, mUserId);
|
||||
});
|
||||
}
|
||||
|
||||
private void launchFingerprintEnroll() {
|
||||
final FingerprintManager fingerprintManager = mActivity
|
||||
.getSystemService(FingerprintManager.class);
|
||||
fingerprintManager.generateChallenge(((sensorId, challenge) -> {
|
||||
final byte[] hardwareAuthToken = BiometricUtils.requestGatekeeperHat(mActivity,
|
||||
mGkPwHandle, mUserId, challenge);
|
||||
final Intent intent = BiometricUtils.getFingerprintIntroIntent(mActivity,
|
||||
mActivity.getIntent());
|
||||
BiometricUtils.launchEnrollForResult(mActivity, intent, REQUEST_FINGERPRINT_ENROLL,
|
||||
hardwareAuthToken, mGkPwHandle, mUserId);
|
||||
}));
|
||||
}
|
||||
|
||||
void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Log.d(TAG, "RequestCode: " + requestCode + " resultCode: " + resultCode);
|
||||
if (resultCode != Activity.RESULT_CANCELED) {
|
||||
BiometricUtils.removeGatekeeperPasswordHandle(mActivity, mGkPwHandle);
|
||||
mActivity.setResult(resultCode);
|
||||
mActivity.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import android.widget.TextView;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
@@ -183,6 +184,7 @@ public class FaceEnrollEducation extends BiometricEnrollBase {
|
||||
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
|
||||
}
|
||||
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
|
||||
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
|
||||
final String flattenedString = getString(R.string.config_face_enroll);
|
||||
if (!TextUtils.isEmpty(flattenedString)) {
|
||||
ComponentName componentName = ComponentName.unflattenFromString(flattenedString);
|
||||
|
||||
@@ -16,17 +16,23 @@
|
||||
|
||||
package com.android.settings.biometrics.face;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorProperties;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.biometrics.MultiBiometricEnrollHelper;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
@@ -37,6 +43,8 @@ import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
import com.google.android.setupdesign.template.RequireScrollMixin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
private static final String TAG = "FaceEnrollIntroduction";
|
||||
@@ -44,6 +52,20 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
private FaceManager mFaceManager;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
@Override
|
||||
protected void onCancelButtonClick(View view) {
|
||||
if (!BiometricUtils.tryStartingNextBiometricEnroll(this, ENROLL_NEXT_BIOMETRIC_REQUEST)) {
|
||||
super.onCancelButtonClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSkipButtonClick(View view) {
|
||||
if (!BiometricUtils.tryStartingNextBiometricEnroll(this, ENROLL_NEXT_BIOMETRIC_REQUEST)) {
|
||||
super.onSkipButtonClick(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -53,25 +75,14 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
.getFaceFeatureProvider();
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_no_thanks)
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||
.setTheme(R.style.SudGlifButton_Secondary)
|
||||
.build()
|
||||
);
|
||||
} else {
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_no_thanks)
|
||||
.setListener(this::onCancelButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.CANCEL)
|
||||
.setTheme(R.style.SudGlifButton_Secondary)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_no_thanks)
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||
.setTheme(R.style.SudGlifButton_Secondary)
|
||||
.build()
|
||||
);
|
||||
|
||||
FooterButton.Builder nextButtonBuilder = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_agree)
|
||||
@@ -99,13 +110,15 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
// 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.containsGatekeeperPassword(getIntent())) {
|
||||
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
||||
mFooterBarMixin.getPrimaryButton().setEnabled(false);
|
||||
// We either block on generateChallenge, or need to gray out the "next" button until
|
||||
// the challenge is ready. Let's just do this for now.
|
||||
mFaceManager.generateChallenge((sensorId, challenge) -> {
|
||||
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
|
||||
BiometricUtils.removeGatekeeperPasswordHandle(this, getIntent());
|
||||
if (BiometricUtils.isMultiBiometricEnrollmentFlow(this)) {
|
||||
BiometricUtils.removeGatekeeperPasswordHandle(this, getIntent());
|
||||
}
|
||||
mFooterBarMixin.getPrimaryButton().setEnabled(true);
|
||||
});
|
||||
}
|
||||
@@ -160,8 +173,9 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
private boolean maxFacesEnrolled() {
|
||||
if (mFaceManager != null) {
|
||||
final int max = getResources().getInteger(
|
||||
com.android.internal.R.integer.config_faceMaxTemplatesPerUser);
|
||||
final List<FaceSensorProperties> props = mFaceManager.getSensorProperties();
|
||||
// This will need to be updated for devices with multiple face sensors.
|
||||
final int max = props.get(0).maxTemplatesAllowed;
|
||||
final int numEnrolledFaces = mFaceManager.getEnrolledFaces(mUserId).size();
|
||||
return numEnrolledFaces >= max;
|
||||
} else {
|
||||
|
||||
@@ -236,7 +236,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (mToken == null && !BiometricUtils.containsGatekeeperPassword(data)) {
|
||||
if (mToken == null && !BiometricUtils.containsGatekeeperPasswordHandle(data)) {
|
||||
Log.e(TAG, "No credential");
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase {
|
||||
|
||||
// This is an entry point for SetNewPasswordController, e.g.
|
||||
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
|
||||
if (mToken == null && BiometricUtils.containsGatekeeperPassword(getIntent())) {
|
||||
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
||||
final FingerprintManager fpm = getSystemService(FingerprintManager.class);
|
||||
fpm.generateChallenge((sensorId, challenge) -> {
|
||||
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
|
||||
@@ -79,6 +79,9 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase {
|
||||
} else if (mToken != null) {
|
||||
// HAT passed in from somewhere else, such as FingerprintEnrollIntroduction
|
||||
startLookingForFingerprint();
|
||||
} else {
|
||||
// There's something wrong with the enrollment flow, this should never happen.
|
||||
throw new IllegalStateException("HAT and GkPwHandle both missing...");
|
||||
}
|
||||
|
||||
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
@@ -28,6 +29,7 @@ import android.widget.TextView;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
@@ -36,6 +38,8 @@ import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
private static final String TAG = "FingerprintIntro";
|
||||
@@ -45,13 +49,14 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mFingerprintManager = Utils.getFingerprintManagerOrNull(this);
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_cancel)
|
||||
.setListener(this::onCancelButtonClick)
|
||||
.setText(getNegativeButtonTextId())
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.SKIP)
|
||||
.setTheme(R.style.SudGlifButton_Secondary)
|
||||
.build()
|
||||
@@ -67,6 +72,10 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
);
|
||||
}
|
||||
|
||||
int getNegativeButtonTextId() {
|
||||
return R.string.security_settings_fingerprint_enroll_introduction_no_thanks;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDisabledByAdmin() {
|
||||
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
||||
@@ -117,8 +126,10 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
@Override
|
||||
protected int checkMaxEnrolled() {
|
||||
if (mFingerprintManager != null) {
|
||||
final int max = getResources().getInteger(
|
||||
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
|
||||
final List<FingerprintSensorProperties> props =
|
||||
mFingerprintManager.getSensorProperties();
|
||||
// This will need to be updated for devices with multiple fingerprint sensors
|
||||
final int max = props.get(0).maxTemplatesAllowed;
|
||||
final int numEnrolledFingerprints =
|
||||
mFingerprintManager.getEnrolledFingerprints(mUserId).size();
|
||||
if (numEnrolledFingerprints >= max) {
|
||||
@@ -147,7 +158,12 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
|
||||
@Override
|
||||
protected Intent getEnrollingIntent() {
|
||||
return new Intent(this, FingerprintEnrollFindSensor.class);
|
||||
final Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
|
||||
if (BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
BiometricUtils.getGatekeeperPasswordHandle(getIntent()));
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -570,7 +570,7 @@ public class FingerprintSettings extends SubSettings {
|
||||
if (requestCode == CONFIRM_REQUEST || requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
|
||||
mLaunchedConfirm = false;
|
||||
if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) {
|
||||
if (data != null && BiometricUtils.containsGatekeeperPassword(data)) {
|
||||
if (data != null && BiometricUtils.containsGatekeeperPasswordHandle(data)) {
|
||||
mFingerprintManager.generateChallenge((sensorId, challenge) -> {
|
||||
mToken = BiometricUtils.requestGatekeeperHat(getActivity(), data,
|
||||
mUserId, challenge);
|
||||
|
||||
@@ -32,7 +32,9 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.SetupChooseLockGeneric;
|
||||
import com.android.settings.password.SetupSkipDialog;
|
||||
|
||||
@@ -58,29 +60,24 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int getNegativeButtonTextId() {
|
||||
return R.string.security_settings_face_enroll_introduction_cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(KEY_LOCK_SCREEN_PRESENT, mAlreadyHadLockScreenSetup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent getChooseLockIntent() {
|
||||
Intent intent = new Intent(this, SetupChooseLockGeneric.class);
|
||||
|
||||
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
|
||||
intent.putExtra(
|
||||
LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
|
||||
intent.putExtra(ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, true);
|
||||
}
|
||||
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent getEnrollingIntent() {
|
||||
final Intent intent = new Intent(this, SetupFingerprintEnrollFindSensor.class);
|
||||
if (BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
BiometricUtils.getGatekeeperPasswordHandle(getIntent()));
|
||||
}
|
||||
SetupWizardUtils.copySetupExtras(getIntent(), intent);
|
||||
return intent;
|
||||
}
|
||||
@@ -157,6 +154,11 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSkipButtonClick(View view) {
|
||||
onCancelButtonClick(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate lock screen metrics if the user goes back from the fingerprint setup screen
|
||||
* after having added lock screen to his device.
|
||||
|
||||
@@ -103,6 +103,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
private static final String TAG = "ChooseLockGenericFragment";
|
||||
private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
|
||||
private static final String KEY_SKIP_FACE = "unlock_skip_face";
|
||||
private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics";
|
||||
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";
|
||||
@@ -175,6 +176,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
|
||||
protected boolean mForFingerprint = false;
|
||||
protected boolean mForFace = false;
|
||||
protected boolean mForBiometrics = false;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -216,6 +218,9 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
mForFace = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
mForBiometrics = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
|
||||
mRequestedMinComplexity = intent
|
||||
.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||
mCallerAppName =
|
||||
@@ -303,17 +308,20 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
}
|
||||
|
||||
protected void addHeaderView() {
|
||||
setHeaderView(R.layout.choose_lock_generic_biometric_header);
|
||||
TextView textView = getHeaderView().findViewById(R.id.biometric_header_description);
|
||||
|
||||
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);
|
||||
textView.setText(R.string.fingerprint_unlock_title);
|
||||
}
|
||||
} else if (mForFace) {
|
||||
setHeaderView(R.layout.choose_lock_generic_face_header);
|
||||
if (mIsSetNewPassword) {
|
||||
((TextView) getHeaderView().findViewById(R.id.face_header_description))
|
||||
.setText(R.string.face_unlock_title);
|
||||
textView.setText(R.string.face_unlock_title);
|
||||
}
|
||||
} else if (mForBiometrics) {
|
||||
if (mIsSetNewPassword) {
|
||||
textView.setText(R.string.biometrics_unlock_title);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,7 +336,8 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
// unlock method to an insecure one
|
||||
showFactoryResetProtectionWarningDialog(key);
|
||||
return true;
|
||||
} else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)) {
|
||||
} else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)
|
||||
|| KEY_SKIP_BIOMETRICS.equals(key)) {
|
||||
Intent chooseLockGenericIntent = new Intent(getActivity(),
|
||||
getInternalActivityClass());
|
||||
chooseLockGenericIntent.setAction(getIntent().getAction());
|
||||
@@ -357,7 +366,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
* @param disabled
|
||||
*/
|
||||
// TODO: why does this take disabled, its always called with a quality higher than
|
||||
// what makes sense with disabled == true
|
||||
// what makes sense with disabled == true
|
||||
private void maybeEnableEncryption(int quality, boolean disabled) {
|
||||
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
|
||||
if (UserManager.get(getActivity()).isAdminUser()
|
||||
@@ -381,8 +390,8 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
unlockMethodIntent);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
|
||||
mForFingerprint);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE,
|
||||
mForFace);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, mForFace);
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, mForBiometrics);
|
||||
// If the caller requested Gatekeeper Password to be returned, we assume it came
|
||||
// from biometric enrollment. This should be cleaned up, since requesting
|
||||
// Gatekeeper Password should not imply it came from biometric setup/settings.
|
||||
@@ -531,6 +540,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
|
||||
findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
|
||||
findPreference(KEY_SKIP_FACE).setViewId(R.id.lock_none);
|
||||
findPreference(KEY_SKIP_BIOMETRICS).setViewId(R.id.lock_none);
|
||||
findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
|
||||
findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
|
||||
}
|
||||
@@ -569,6 +579,12 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
setPreferenceTitle(ScreenLockType.PIN, R.string.face_unlock_set_unlock_pin);
|
||||
setPreferenceTitle(ScreenLockType.PASSWORD,
|
||||
R.string.face_unlock_set_unlock_password);
|
||||
} else if (mForBiometrics) {
|
||||
setPreferenceTitle(ScreenLockType.PATTERN,
|
||||
R.string.biometrics_unlock_set_unlock_pattern);
|
||||
setPreferenceTitle(ScreenLockType.PIN, R.string.biometrics_unlock_set_unlock_pin);
|
||||
setPreferenceTitle(ScreenLockType.PASSWORD,
|
||||
R.string.biometrics_unlock_set_unlock_password);
|
||||
}
|
||||
|
||||
if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
|
||||
@@ -584,6 +600,9 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
if (!(mForFace && mIsSetNewPassword)) {
|
||||
removePreference(KEY_SKIP_FACE);
|
||||
}
|
||||
if (!(mForBiometrics && mIsSetNewPassword)) {
|
||||
removePreference(KEY_SKIP_BIOMETRICS);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
|
||||
@@ -727,6 +746,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
.setRequestedMinComplexity(mRequestedMinComplexity)
|
||||
.setForFingerprint(mForFingerprint)
|
||||
.setForFace(mForFace)
|
||||
.setForBiometrics(mForBiometrics)
|
||||
.setUserId(mUserId)
|
||||
.setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
|
||||
if (mUserPassword != null) {
|
||||
@@ -743,6 +763,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
new ChooseLockPattern.IntentBuilder(getContext())
|
||||
.setForFingerprint(mForFingerprint)
|
||||
.setForFace(mForFace)
|
||||
.setForBiometrics(mForBiometrics)
|
||||
.setUserId(mUserId)
|
||||
.setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
|
||||
if (mUserPassword != null) {
|
||||
|
||||
@@ -151,6 +151,11 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntentBuilder setForBiometrics(boolean forBiometrics) {
|
||||
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntentBuilder setRequestedMinComplexity(@PasswordComplexity int level) {
|
||||
mIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, level);
|
||||
return this;
|
||||
@@ -190,12 +195,16 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
final boolean forFace = getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
final boolean forBiometrics = getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
|
||||
CharSequence msg = getText(R.string.lockpassword_choose_your_screen_lock_header);
|
||||
if (forFingerprint) {
|
||||
msg = getText(R.string.lockpassword_choose_your_password_header_for_fingerprint);
|
||||
} else if (forFace) {
|
||||
msg = getText(R.string.lockpassword_choose_your_password_header_for_face);
|
||||
} else if (forBiometrics) {
|
||||
msg = getText(R.string.lockpassword_choose_your_password_header_for_biometrics);
|
||||
}
|
||||
|
||||
setTitle(msg);
|
||||
@@ -232,6 +241,7 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
private GlifLayout mLayout;
|
||||
protected boolean mForFingerprint;
|
||||
protected boolean mForFace;
|
||||
protected boolean mForBiometrics;
|
||||
|
||||
private LockscreenCredential mFirstPassword;
|
||||
private RecyclerView mPasswordRestrictionView;
|
||||
@@ -254,9 +264,11 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
R.string.lockpassword_choose_your_screen_lock_header, // password
|
||||
R.string.lockpassword_choose_your_password_header_for_fingerprint,
|
||||
R.string.lockpassword_choose_your_password_header_for_face,
|
||||
R.string.lockpassword_choose_your_password_header_for_biometrics,
|
||||
R.string.lockpassword_choose_your_screen_lock_header, // pin
|
||||
R.string.lockpassword_choose_your_pin_header_for_fingerprint,
|
||||
R.string.lockpassword_choose_your_pin_header_for_face,
|
||||
R.string.lockpassword_choose_your_pin_header_for_biometrics,
|
||||
R.string.lockpassword_choose_your_password_message, // added security message
|
||||
R.string.lock_settings_picker_biometrics_added_security_message,
|
||||
R.string.lockpassword_choose_your_pin_message,
|
||||
@@ -267,6 +279,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
R.string.lockpassword_confirm_your_password_header,
|
||||
R.string.lockpassword_confirm_your_password_header,
|
||||
R.string.lockpassword_confirm_your_password_header,
|
||||
R.string.lockpassword_confirm_your_password_header,
|
||||
R.string.lockpassword_confirm_your_pin_header,
|
||||
R.string.lockpassword_confirm_your_pin_header,
|
||||
R.string.lockpassword_confirm_your_pin_header,
|
||||
R.string.lockpassword_confirm_your_pin_header,
|
||||
@@ -280,6 +294,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
R.string.lockpassword_confirm_passwords_dont_match,
|
||||
R.string.lockpassword_confirm_passwords_dont_match,
|
||||
R.string.lockpassword_confirm_passwords_dont_match,
|
||||
R.string.lockpassword_confirm_passwords_dont_match,
|
||||
R.string.lockpassword_confirm_pins_dont_match,
|
||||
R.string.lockpassword_confirm_pins_dont_match,
|
||||
R.string.lockpassword_confirm_pins_dont_match,
|
||||
R.string.lockpassword_confirm_pins_dont_match,
|
||||
@@ -289,18 +305,22 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
0,
|
||||
R.string.lockpassword_confirm_label);
|
||||
|
||||
Stage(int hintInAlpha, int hintInAlphaForFingerprint, int hintInAlphaForFace,
|
||||
int hintInNumeric, int hintInNumericForFingerprint, int hintInNumericForFace,
|
||||
Stage(int hintInAlpha,
|
||||
int hintInAlphaForFingerprint, int hintInAlphaForFace, int hintInAlphaForBiometrics,
|
||||
int hintInNumeric,
|
||||
int hintInNumericForFingerprint, int hintInNumericForFace, int hintInNumericForBiometrics,
|
||||
int messageInAlpha, int messageInAlphaForBiometrics,
|
||||
int messageInNumeric, int messageInNumericForBiometrics,
|
||||
int nextButtonText) {
|
||||
this.alphaHint = hintInAlpha;
|
||||
this.alphaHintForFingerprint = hintInAlphaForFingerprint;
|
||||
this.alphaHintForFace = hintInAlphaForFace;
|
||||
this.alphaHintForBiometrics = hintInAlphaForBiometrics;
|
||||
|
||||
this.numericHint = hintInNumeric;
|
||||
this.numericHintForFingerprint = hintInNumericForFingerprint;
|
||||
this.numericHintForFace = hintInNumericForFace;
|
||||
this.numericHintForBiometrics = hintInNumericForBiometrics;
|
||||
|
||||
this.alphaMessage = messageInAlpha;
|
||||
this.alphaMessageForBiometrics = messageInAlphaForBiometrics;
|
||||
@@ -312,16 +332,19 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
public static final int TYPE_NONE = 0;
|
||||
public static final int TYPE_FINGERPRINT = 1;
|
||||
public static final int TYPE_FACE = 2;
|
||||
public static final int TYPE_BIOMETRIC = 3;
|
||||
|
||||
// Password
|
||||
public final int alphaHint;
|
||||
public final int alphaHintForFingerprint;
|
||||
public final int alphaHintForFace;
|
||||
public final int alphaHintForBiometrics;
|
||||
|
||||
// PIN
|
||||
public final int numericHint;
|
||||
public final int numericHintForFingerprint;
|
||||
public final int numericHintForFace;
|
||||
public final int numericHintForBiometrics;
|
||||
|
||||
public final int alphaMessage;
|
||||
public final int alphaMessageForBiometrics;
|
||||
@@ -335,6 +358,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return alphaHintForFingerprint;
|
||||
} else if (type == TYPE_FACE) {
|
||||
return alphaHintForFace;
|
||||
} else if (type == TYPE_BIOMETRIC) {
|
||||
return alphaHintForBiometrics;
|
||||
} else {
|
||||
return alphaHint;
|
||||
}
|
||||
@@ -343,6 +368,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
return numericHintForFingerprint;
|
||||
} else if (type == TYPE_FACE) {
|
||||
return numericHintForFace;
|
||||
} else if (type == TYPE_BIOMETRIC) {
|
||||
return numericHintForBiometrics;
|
||||
} else {
|
||||
return numericHint;
|
||||
}
|
||||
@@ -376,6 +403,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mForFingerprint = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
mForBiometrics = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
mMinComplexity = intent.getIntExtra(
|
||||
EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
|
||||
|
||||
@@ -454,6 +483,8 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_fingerprint_header));
|
||||
} else if (mForFace) {
|
||||
mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_face_header));
|
||||
} else if (mForBiometrics) {
|
||||
mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_lock));
|
||||
}
|
||||
|
||||
mIsAlphaMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == mRequestedQuality
|
||||
@@ -546,9 +577,15 @@ public class ChooseLockPassword extends SettingsActivity {
|
||||
}
|
||||
|
||||
protected int getStageType() {
|
||||
return mForFingerprint ? Stage.TYPE_FINGERPRINT :
|
||||
mForFace ? Stage.TYPE_FACE :
|
||||
Stage.TYPE_NONE;
|
||||
if (mForFingerprint) {
|
||||
return Stage.TYPE_FINGERPRINT;
|
||||
} else if (mForFace) {
|
||||
return Stage.TYPE_FACE;
|
||||
} else if (mForBiometrics) {
|
||||
return Stage.TYPE_BIOMETRIC;
|
||||
} else {
|
||||
return Stage.TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPasswordRequirementsView(View view) {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
* behavior. So, now an activity does not finish itself until it gets this
|
||||
* result.
|
||||
*/
|
||||
static final int RESULT_FINISHED = RESULT_FIRST_USER;
|
||||
public static final int RESULT_FINISHED = RESULT_FIRST_USER;
|
||||
|
||||
private static final String TAG = "ChooseLockPattern";
|
||||
|
||||
@@ -134,6 +134,11 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
return this;
|
||||
}
|
||||
|
||||
public IntentBuilder setForBiometrics(boolean forBiometrics) {
|
||||
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the launch such that at the end of the pattern enrollment, one of its
|
||||
* managed profile (specified by {@code profileId}) will have its lockscreen unified
|
||||
@@ -455,6 +460,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
protected int mUserId;
|
||||
protected boolean mForFingerprint;
|
||||
protected boolean mForFace;
|
||||
protected boolean mForBiometrics;
|
||||
|
||||
private static final String KEY_UI_STAGE = "uiStage";
|
||||
private static final String KEY_PATTERN_CHOICE = "chosenPattern";
|
||||
@@ -488,6 +494,8 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
mForFace = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
mForBiometrics = intent.getBooleanExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -506,6 +514,8 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
layout.setIcon(getActivity().getDrawable(R.drawable.ic_fingerprint_header));
|
||||
} else if (mForFace) {
|
||||
layout.setIcon(getActivity().getDrawable(R.drawable.ic_face_header));
|
||||
} else if (mForBiometrics) {
|
||||
layout.setIcon(getActivity().getDrawable(R.drawable.ic_lock));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,8 +742,8 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
} else {
|
||||
mHeaderText.setText(stage.headerMessage);
|
||||
}
|
||||
final boolean forBiometrics = mForFingerprint || mForFace;
|
||||
int message = forBiometrics ? stage.messageForBiometrics : stage.message;
|
||||
final boolean forAnyBiometric = mForFingerprint || mForFace || mForBiometrics;
|
||||
int message = forAnyBiometric ? stage.messageForBiometrics : stage.message;
|
||||
if (message == ID_EMPTY_MESSAGE) {
|
||||
mMessageText.setText("");
|
||||
} else {
|
||||
@@ -756,7 +766,7 @@ public class ChooseLockPattern extends SettingsActivity {
|
||||
mHeaderText.setTextColor(mDefaultHeaderColorList);
|
||||
}
|
||||
|
||||
if (stage == Stage.NeedToConfirm && forBiometrics) {
|
||||
if (stage == Stage.NeedToConfirm && forAnyBiometric) {
|
||||
mHeaderText.setText("");
|
||||
mTitleText.setText(R.string.lockpassword_draw_your_pattern_again_header);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,12 @@ public final class ChooseLockSettingsHelper {
|
||||
public static final String EXTRA_KEY_FORCE_VERIFY = "force_verify";
|
||||
// Gatekeeper HardwareAuthToken
|
||||
public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
|
||||
// For the fingerprint-only path
|
||||
public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
|
||||
// For the face-only path
|
||||
public static final String EXTRA_KEY_FOR_FACE = "for_face";
|
||||
// For the paths where multiple biometric sensors exist
|
||||
public static final String EXTRA_KEY_FOR_BIOMETRICS = "for_biometrics";
|
||||
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
|
||||
public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only";
|
||||
public static final String EXTRA_KEY_REQUEST_GK_PW_HANDLE = "request_gk_pw_handle";
|
||||
|
||||
@@ -111,28 +111,49 @@ final class SetNewPasswordController {
|
||||
*/
|
||||
public void dispatchSetNewPasswordIntent() {
|
||||
final Bundle extras;
|
||||
// TODO: handle the case with multiple biometrics, perhaps take an arg for biometric type?
|
||||
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)
|
||||
&& mFaceManager != null
|
||||
&& mFaceManager.isHardwareDetected()
|
||||
&& !mFaceManager.hasEnrolledTemplates(mTargetUserId)
|
||||
&& !isFaceDisabledByAdmin()) {
|
||||
extras = getFaceChooseLockExtras();
|
||||
} else if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
|
||||
&& mFingerprintManager != null
|
||||
|
||||
final boolean hasFeatureFingerprint = mPackageManager
|
||||
.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
final boolean hasFeatureFace = mPackageManager
|
||||
.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
|
||||
final boolean shouldShowFingerprintEnroll = mFingerprintManager != null
|
||||
&& mFingerprintManager.isHardwareDetected()
|
||||
&& !mFingerprintManager.hasEnrolledFingerprints(mTargetUserId)
|
||||
&& !isFingerprintDisabledByAdmin()) {
|
||||
&& !isFingerprintDisabledByAdmin();
|
||||
final boolean shouldShowFaceEnroll = mFaceManager != null
|
||||
&& mFaceManager.isHardwareDetected()
|
||||
&& !mFaceManager.hasEnrolledTemplates(mTargetUserId)
|
||||
&& !isFaceDisabledByAdmin();
|
||||
|
||||
if (hasFeatureFace && shouldShowFaceEnroll
|
||||
&& hasFeatureFingerprint && shouldShowFingerprintEnroll) {
|
||||
extras = getBiometricChooseLockExtras();
|
||||
} else if (hasFeatureFace && shouldShowFaceEnroll) {
|
||||
extras = getFaceChooseLockExtras();
|
||||
} else if (hasFeatureFingerprint && shouldShowFingerprintEnroll) {
|
||||
extras = getFingerprintChooseLockExtras();
|
||||
} else {
|
||||
extras = new Bundle();
|
||||
}
|
||||
|
||||
// No matter we show fingerprint options or not, we should tell the next activity which
|
||||
// user is setting new password.
|
||||
extras.putInt(Intent.EXTRA_USER_ID, mTargetUserId);
|
||||
mUi.launchChooseLock(extras);
|
||||
}
|
||||
|
||||
private Bundle getBiometricChooseLockExtras() {
|
||||
Bundle chooseLockExtras = new Bundle();
|
||||
chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
chooseLockExtras.putBoolean(
|
||||
ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
|
||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
|
||||
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
|
||||
return chooseLockExtras;
|
||||
}
|
||||
|
||||
private Bundle getFingerprintChooseLockExtras() {
|
||||
Bundle chooseLockExtras = new Bundle();
|
||||
chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
||||
|
||||
@@ -200,8 +200,9 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
|
||||
/* isPatternMode= */ false,
|
||||
/* isAlphaMode= */ false,
|
||||
/* isFingerprintSupported= */ false,
|
||||
/* isFaceSupported= */ false
|
||||
/* forFingerprint= */ false,
|
||||
/* forFace= */ false,
|
||||
/* forBiometrics= */ false
|
||||
);
|
||||
dialog.show(getFragmentManager());
|
||||
return true;
|
||||
@@ -242,7 +243,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
|
||||
}
|
||||
|
||||
private boolean isForBiometric() {
|
||||
return mForFingerprint || mForFace;
|
||||
return mForFingerprint || mForFace || mForBiometrics;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,18 +104,23 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
|
||||
@Override
|
||||
protected void onSkipOrClearButtonClick(View view) {
|
||||
if (mLeftButtonIsSkip) {
|
||||
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
|
||||
final Intent intent = getActivity().getIntent();
|
||||
final boolean frpSupported = intent
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false);
|
||||
final boolean forFingerprint = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
final boolean forFace = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
final boolean forBiometrics = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
|
||||
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
frpSupported,
|
||||
/* isPatternMode= */ false,
|
||||
mIsAlphaMode,
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
|
||||
false),
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false)
|
||||
|
||||
);
|
||||
forFingerprint,
|
||||
forFace,
|
||||
forBiometrics);
|
||||
dialog.show(getFragmentManager());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,18 +90,23 @@ public class SetupChooseLockPattern extends ChooseLockPattern {
|
||||
@Override
|
||||
protected void onSkipOrClearButtonClick(View view) {
|
||||
if (mLeftButtonIsSkip) {
|
||||
SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false),
|
||||
final Intent intent = getActivity().getIntent();
|
||||
final boolean frpSupported = intent
|
||||
.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false);
|
||||
final boolean forFingerprint = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
|
||||
final boolean forFace = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
|
||||
final boolean forBiometrics = intent
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
|
||||
|
||||
final SetupSkipDialog dialog = SetupSkipDialog.newInstance(
|
||||
frpSupported,
|
||||
/* isPatternMode= */ true,
|
||||
/* isAlphaMode= */ false,
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
|
||||
false),
|
||||
getActivity().getIntent()
|
||||
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false)
|
||||
|
||||
);
|
||||
forFingerprint,
|
||||
forFace,
|
||||
forBiometrics);
|
||||
dialog.show(getFragmentManager());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,14 +43,16 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
public static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10;
|
||||
|
||||
public static SetupSkipDialog newInstance(boolean isFrpSupported, boolean isPatternMode,
|
||||
boolean isAlphanumericMode, boolean isFingerprintSupported, boolean isFaceSupported) {
|
||||
boolean isAlphanumericMode, boolean forFingerprint, boolean forFace,
|
||||
boolean forBiometrics) {
|
||||
SetupSkipDialog dialog = new SetupSkipDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(ARG_FRP_SUPPORTED, isFrpSupported);
|
||||
args.putBoolean(ARG_LOCK_TYPE_PATTERN, isPatternMode);
|
||||
args.putBoolean(ARG_LOCK_TYPE_ALPHANUMERIC, isAlphanumericMode);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, isFingerprintSupported);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, isFaceSupported);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace);
|
||||
args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics);
|
||||
dialog.setArguments(args);
|
||||
return dialog;
|
||||
}
|
||||
@@ -68,11 +70,13 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
@NonNull
|
||||
public AlertDialog.Builder onCreateDialogBuilder() {
|
||||
Bundle args = getArguments();
|
||||
final boolean isFaceSupported =
|
||||
final boolean forFace =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE);
|
||||
final boolean isFingerprintSupported =
|
||||
final boolean forFingerprint =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT);
|
||||
if (isFaceSupported || isFingerprintSupported) {
|
||||
final boolean forBiometrics =
|
||||
args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS);
|
||||
if (forFace || forFingerprint || forBiometrics) {
|
||||
final int titleId;
|
||||
|
||||
if (args.getBoolean(ARG_LOCK_TYPE_PATTERN)) {
|
||||
@@ -82,13 +86,20 @@ public class SetupSkipDialog extends InstrumentedDialogFragment
|
||||
R.string.lock_screen_password_skip_title : R.string.lock_screen_pin_skip_title;
|
||||
}
|
||||
|
||||
final int msgResId;
|
||||
if (forBiometrics) {
|
||||
msgResId = R.string.biometrics_lock_screen_setup_skip_dialog_text;
|
||||
} else if (forFace) {
|
||||
msgResId = R.string.face_lock_screen_setup_skip_dialog_text;
|
||||
} else {
|
||||
msgResId = R.string.fingerprint_lock_screen_setup_skip_dialog_text;
|
||||
}
|
||||
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this)
|
||||
.setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this)
|
||||
.setTitle(titleId)
|
||||
.setMessage(isFaceSupported ?
|
||||
R.string.face_lock_screen_setup_skip_dialog_text :
|
||||
R.string.fingerprint_lock_screen_setup_skip_dialog_text);
|
||||
.setMessage(msgResId);
|
||||
} else {
|
||||
return new AlertDialog.Builder(getContext())
|
||||
.setPositiveButton(R.string.skip_anyway_button_label, this)
|
||||
|
||||
Reference in New Issue
Block a user