1/n: Prepare ConfirmDeviceCredentials to use BiometricPrompt

CDC is going to use BiometricPrompt instead. This change
removes FingerprintManager from CDC. BiometricPrompt
will show before pin/pattern/pass is shown.

Bug: 111461540

Test: modified BiometricPromptDemo to use
      KeyguardManager#createConfirmDeviceCredentialIntent,
Test: Fingerprint is gone from CDC, rotation works
Test: atest SettingsRoboTests

Change-Id: I9ce2aad71961af8a0d5ee636600e2fbdb6154e47
This commit is contained in:
Kevin Chyn
2018-10-03 18:39:22 -07:00
parent dd3feeb155
commit e5a016e076
13 changed files with 6 additions and 307 deletions

View File

@@ -1,30 +0,0 @@
<!--
~ Copyright (C) 2015 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
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32.0"
android:viewportHeight="32.0">
<path
android:fillColor="?android:attr/colorError"
android:pathData="M15.99,2.5C8.53,2.5 2.5,8.54 2.5,16.0s6.03,13.5 13.49,13.5S29.5,23.46 29.5,16.0S23.45,2.5 15.99,2.5zM16.0,26.8c-5.97,0.0 -10.8,-4.83 -10.8,-10.8S10.03,5.2 16.0,5.2S26.8,10.03 26.8,16.0S21.97,26.8 16.0,26.8z"/>
<path
android:fillColor="?android:attr/colorError"
android:pathData="M14.65,20.05l2.7,0.0l0.0,2.7l-2.7,0.0z"/>
<path
android:fillColor="?android:attr/colorError"
android:pathData="M14.65,9.25l2.7,0.0l0.0,8.1l-2.7,0.0z"/>
</vector>

View File

@@ -87,14 +87,6 @@
</LinearLayout> </LinearLayout>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="end|bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="28dp"
android:layout_marginEnd="20dp"
android:visibility="gone"/>
</FrameLayout> </FrameLayout>
</LinearLayout> </LinearLayout>

View File

@@ -108,14 +108,6 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1"/> android:layout_weight="1"/>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout> </LinearLayout>
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient> </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>

View File

@@ -85,14 +85,6 @@
android:layout_marginEnd="?attr/suwMarginSides" android:layout_marginEnd="?attr/suwMarginSides"
android:layout_marginBottom="24dp" android:layout_marginBottom="24dp"
android:gravity="center_vertical"/> android:gravity="center_vertical"/>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/confirm_fingerprint_icon_content_description"
android:visibility="gone"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@@ -89,19 +89,5 @@
</LinearLayout> </LinearLayout>
<View android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="24dp"
android:contentDescription="@string/confirm_fingerprint_icon_content_description"
android:visibility="gone"/>
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient> </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
</FrameLayout> </FrameLayout>

View File

@@ -70,16 +70,6 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1" />
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="24dp"
android:contentDescription="@string/confirm_fingerprint_icon_content_description"
android:visibility="gone"/>
<Button <Button
android:id="@+id/cancelButton" android:id="@+id/cancelButton"
style="@style/SuwGlifButton.Secondary" style="@style/SuwGlifButton.Secondary"

View File

@@ -97,15 +97,6 @@
android:layout_marginEnd="12dp" android:layout_marginEnd="12dp"
android:gravity="center_vertical"/> android:gravity="center_vertical"/>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="24dp"
android:contentDescription="@string/confirm_fingerprint_icon_content_description"
android:visibility="gone"/>
</LinearLayout> </LinearLayout>
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient> </com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>

View File

@@ -90,16 +90,6 @@
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:gravity="center_vertical"/> android:gravity="center_vertical"/>
<ImageView
android:id="@+id/fingerprintIcon"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="?attr/suwMarginSides"
android:layout_marginBottom="24dp"
android:contentDescription="@string/confirm_fingerprint_icon_content_description"
android:visibility="gone"/>
<Button <Button
android:id="@+id/cancelButton" android:id="@+id/cancelButton"
style="@style/SuwGlifButton.Secondary" style="@style/SuwGlifButton.Secondary"

View File

@@ -1051,9 +1051,6 @@
<!-- Button to confirm the last removing the last fingerprint. [CHAR LIMIT=20]--> <!-- Button to confirm the last removing the last fingerprint. [CHAR LIMIT=20]-->
<string name="fingerprint_last_delete_confirm">Yes, remove</string> <string name="fingerprint_last_delete_confirm">Yes, remove</string>
<!-- Content description for the fingerprint icon when the user is prompted to enter his credentials. Not shown on the screen. [CHAR LIMIT=NONE] -->
<string name="confirm_fingerprint_icon_content_description">Use your fingerprint to continue.</string>
<!-- Title of the preferences category for preference items to control encryption --> <!-- Title of the preferences category for preference items to control encryption -->
<string name="crypt_keeper_settings_title">Encryption</string> <string name="crypt_keeper_settings_title">Encryption</string>
@@ -3771,8 +3768,8 @@
<string name="lockpassword_confirm_your_password_generic_profile">Enter your work password to continue</string> <string name="lockpassword_confirm_your_password_generic_profile">Enter your work password to continue</string>
<!-- This string shows up on a screen where a user can enter a pattern that <!-- This string shows up on a screen where a user can enter a pattern that
unlocks their device. This is an extra security measure that's required for them to unlocks their device. This is an extra security measure that's required for them to
continue. [CHAR LIMIT=100] --> continue. [CHAR LIMIT=100] -->
<string name="lockpassword_strong_auth_required_device_pattern">For added security, use your device pattern</string> <string name="lockpassword_strong_auth_required_device_pattern">For added security, use your device pattern</string>
<!-- This string shows up on a screen where a user can enter a PIN that unlocks their device. <!-- This string shows up on a screen where a user can enter a PIN that unlocks their device.
This is an extra security measure that's required for them to continue. [CHAR LIMIT=100] This is an extra security measure that's required for them to continue. [CHAR LIMIT=100]
@@ -8371,9 +8368,6 @@
<!-- Explanation that the app that will NEVER be launched to open web links to domains that it understands --> <!-- Explanation that the app that will NEVER be launched to open web links to domains that it understands -->
<string name="app_link_open_never">Don&#8217;t open in this app</string> <string name="app_link_open_never">Don&#8217;t open in this app</string>
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
<!-- Title for Default Apps settings [CHAR LIMIT=30] --> <!-- Title for Default Apps settings [CHAR LIMIT=30] -->
<string name="default_apps_title">Default</string> <string name="default_apps_title">Default</string>

View File

@@ -1,130 +0,0 @@
/*
* Copyright (C) 2015 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.fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.Utils;
/**
* Small helper class to manage text/icon around fingerprint authentication UI.
*/
public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
private static final long ERROR_TIMEOUT = 1300;
private ImageView mIcon;
private TextView mErrorTextView;
private CancellationSignal mCancellationSignal;
private int mUserId;
private Callback mCallback;
private FingerprintManager mFingerprintManager;
public FingerprintUiHelper(ImageView icon, TextView errorTextView, Callback callback,
int userId) {
mFingerprintManager = Utils.getFingerprintManagerOrNull(icon.getContext());
mIcon = icon;
mErrorTextView = errorTextView;
mCallback = callback;
mUserId = userId;
}
public void startListening() {
if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.getEnrolledFingerprints(mUserId).size() > 0) {
mCancellationSignal = new CancellationSignal();
mFingerprintManager.setActiveUser(mUserId);
mFingerprintManager.authenticate(
null, mCancellationSignal, 0 /* flags */, this, null, mUserId);
setFingerprintIconVisibility(true);
mIcon.setImageResource(R.drawable.ic_fingerprint);
}
}
public void stopListening() {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
mCancellationSignal = null;
}
}
public boolean isListening() {
return mCancellationSignal != null && !mCancellationSignal.isCanceled();
}
private void setFingerprintIconVisibility(boolean visible) {
mIcon.setVisibility(visible ? View.VISIBLE : View.GONE);
mCallback.onFingerprintIconVisibilityChanged(visible);
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
// Only happens if we get preempted by another activity. Ignored.
return;
}
showError(errString);
setFingerprintIconVisibility(false);
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
showError(helpString);
}
@Override
public void onAuthenticationFailed() {
showError(mIcon.getResources().getString(
R.string.fingerprint_not_recognized));
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
mIcon.setImageResource(R.drawable.ic_fingerprint_success);
mCallback.onAuthenticated();
}
private void showError(CharSequence error) {
if (!isListening()) {
return;
}
mIcon.setImageResource(R.drawable.ic_fingerprint_error);
mErrorTextView.setText(error);
mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT);
}
private Runnable mResetErrorTextRunnable = new Runnable() {
@Override
public void run() {
mErrorTextView.setText("");
mIcon.setImageResource(R.drawable.ic_fingerprint);
}
};
public interface Callback {
void onAuthenticated();
void onFingerprintIconVisibilityChanged(boolean visible);
}
}

View File

@@ -53,14 +53,12 @@ import androidx.fragment.app.FragmentManager;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.biometrics.fingerprint.FingerprintUiHelper;
import com.android.settings.core.InstrumentedFragment; import com.android.settings.core.InstrumentedFragment;
/** /**
* Base fragment to be shared for PIN/Pattern/Password confirmation fragments. * Base fragment to be shared for PIN/Pattern/Password confirmation fragments.
*/ */
public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFragment public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFragment {
implements FingerprintUiHelper.Callback {
public static final String PACKAGE = "com.android.settings"; public static final String PACKAGE = "com.android.settings";
public static final String TITLE_TEXT = PACKAGE + ".ConfirmCredentials.title"; public static final String TITLE_TEXT = PACKAGE + ".ConfirmCredentials.title";
@@ -81,10 +79,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
/** Time we wait before clearing a wrong input attempt (e.g. pattern) and the error message. */ /** Time we wait before clearing a wrong input attempt (e.g. pattern) and the error message. */
protected static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 3000; protected static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 3000;
private FingerprintUiHelper mFingerprintHelper;
protected boolean mReturnCredentials = false; protected boolean mReturnCredentials = false;
protected Button mCancelButton; protected Button mCancelButton;
protected ImageView mFingerprintIcon;
protected int mEffectiveUserId; protected int mEffectiveUserId;
protected int mUserId; protected int mUserId;
protected UserManager mUserManager; protected UserManager mUserManager;
@@ -123,9 +119,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
mCancelButton = (Button) view.findViewById(R.id.cancelButton); mCancelButton = (Button) view.findViewById(R.id.cancelButton);
mFingerprintIcon = (ImageView) view.findViewById(R.id.fingerprintIcon);
mFingerprintHelper = new FingerprintUiHelper(
mFingerprintIcon, view.findViewById(R.id.errorText), this, mUserId);
boolean showCancelButton = getActivity().getIntent().getBooleanExtra( boolean showCancelButton = getActivity().getIntent().getBooleanExtra(
SHOW_CANCEL_BUTTON, false); SHOW_CANCEL_BUTTON, false);
boolean hasAlternateButton = mFrp && !TextUtils.isEmpty(mFrpAlternateButtonText); boolean hasAlternateButton = mFrp && !TextUtils.isEmpty(mFrpAlternateButtonText);
@@ -153,29 +147,16 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
} }
} }
private boolean isFingerprintDisabledByAdmin() {
final int disabledFeatures =
mDevicePolicyManager.getKeyguardDisabledFeatures(null, mEffectiveUserId);
return (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0;
}
// User could be locked while Effective user is unlocked even though the effective owns the // User could be locked while Effective user is unlocked even though the effective owns the
// credential. Otherwise, fingerprint can't unlock fbe/keystore through // credential. Otherwise, fingerprint can't unlock fbe/keystore through
// verifyTiedProfileChallenge. In such case, we also wanna show the user message that // verifyTiedProfileChallenge. In such case, we also wanna show the user message that
// fingerprint is disabled due to device restart. // fingerprint is disabled due to device restart.
protected boolean isStrongAuthRequired() { protected boolean isStrongAuthRequired() {
return mFrp return mFrp
|| !mLockPatternUtils.isFingerprintAllowedForUser(mEffectiveUserId) || !mLockPatternUtils.isBiometricAllowedForUser(mEffectiveUserId)
|| !mUserManager.isUserUnlocked(mUserId); || !mUserManager.isUserUnlocked(mUserId);
} }
private boolean isFingerprintAllowed() {
return !mReturnCredentials
&& getActivity().getIntent().getBooleanExtra(ALLOW_FP_AUTHENTICATION, false)
&& !isStrongAuthRequired()
&& !isFingerprintDisabledByAdmin();
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@@ -183,13 +164,6 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
} }
protected void refreshLockScreen() { protected void refreshLockScreen() {
if (isFingerprintAllowed()) {
mFingerprintHelper.startListening();
} else {
if (mFingerprintHelper.isListening()) {
mFingerprintHelper.stopListening();
}
}
updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId)); updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
} }
@@ -214,28 +188,10 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
if (mFingerprintHelper.isListening()) {
mFingerprintHelper.stopListening();
}
}
@Override
public void onAuthenticated() {
// Check whether we are still active.
if (getActivity() != null && getActivity().isResumed()) {
TrustManager trustManager =
(TrustManager) getActivity().getSystemService(Context.TRUST_SERVICE);
trustManager.setDeviceLockedForUser(mEffectiveUserId, false);
authenticationSucceeded();
checkForPendingIntent();
}
} }
protected abstract void authenticationSucceeded(); protected abstract void authenticationSucceeded();
@Override
public void onFingerprintIconVisibilityChanged(boolean visible) {
}
public void prepareEnterAnimation() { public void prepareEnterAnimation() {
} }

View File

@@ -105,7 +105,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
private CountDownTimer mCountdownTimer; private CountDownTimer mCountdownTimer;
private boolean mIsAlpha; private boolean mIsAlpha;
private InputMethodManager mImm; private InputMethodManager mImm;
private boolean mUsingFingerprint = false;
private AppearAnimationUtils mAppearAnimationUtils; private AppearAnimationUtils mAppearAnimationUtils;
private DisappearAnimationUtils mDisappearAnimationUtils; private DisappearAnimationUtils mDisappearAnimationUtils;
@@ -243,7 +242,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
mCancelButton.setAlpha(0f); mCancelButton.setAlpha(0f);
mPasswordEntry.setAlpha(0f); mPasswordEntry.setAlpha(0f);
mErrorTextView.setAlpha(0f); mErrorTextView.setAlpha(0f);
mFingerprintIcon.setAlpha(0f);
} }
private View[] getActiveViews() { private View[] getActiveViews() {
@@ -255,9 +253,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
} }
result.add(mPasswordEntry); result.add(mPasswordEntry);
result.add(mErrorTextView); result.add(mErrorTextView);
if (mFingerprintIcon.getVisibility() == View.VISIBLE) {
result.add(mFingerprintIcon);
}
return result.toArray(new View[] {}); return result.toArray(new View[] {});
} }
@@ -303,17 +298,12 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
mCredentialCheckResultTracker.setResult(true, new Intent(), 0, mEffectiveUserId); mCredentialCheckResultTracker.setResult(true, new Intent(), 0, mEffectiveUserId);
} }
@Override
public void onFingerprintIconVisibilityChanged(boolean visible) {
mUsingFingerprint = visible;
}
private void updatePasswordEntry() { private void updatePasswordEntry() {
final boolean isLockedOut = final boolean isLockedOut =
mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId) != 0; mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId) != 0;
mPasswordEntry.setEnabled(!isLockedOut); mPasswordEntry.setEnabled(!isLockedOut);
mPasswordEntryInputDisabler.setInputEnabled(!isLockedOut); mPasswordEntryInputDisabler.setInputEnabled(!isLockedOut);
if (isLockedOut || mUsingFingerprint) { if (isLockedOut) {
mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), 0 /*flags*/); mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), 0 /*flags*/);
} else { } else {
mPasswordEntry.scheduleShowSoftInput(); mPasswordEntry.scheduleShowSoftInput();

View File

@@ -231,7 +231,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mCancelButton.setAlpha(0f); mCancelButton.setAlpha(0f);
mLockPatternView.setAlpha(0f); mLockPatternView.setAlpha(0f);
mDetailsTextView.setAlpha(0f); mDetailsTextView.setAlpha(0f);
mFingerprintIcon.setAlpha(0f);
} }
private int getDefaultDetails() { private int getDefaultDetails() {
@@ -265,9 +264,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
} }
result.add(row); result.add(row);
} }
if (mFingerprintIcon.getVisibility() == View.VISIBLE) {
result.add(new ArrayList<Object>(Collections.singletonList(mFingerprintIcon)));
}
Object[][] resultArr = new Object[result.size()][cellStates[0].length]; Object[][] resultArr = new Object[result.size()][cellStates[0].length];
for (int i = 0; i < result.size(); i++) { for (int i = 0; i < result.size(); i++) {
ArrayList<Object> row = result.get(i); ArrayList<Object> row = result.get(i);
@@ -377,16 +373,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
} }
} }
@Override
public void onFingerprintIconVisibilityChanged(boolean visible) {
if (mLeftSpacerLandscape != null && mRightSpacerLandscape != null) {
// In landscape, adjust spacing depending on fingerprint icon visibility.
mLeftSpacerLandscape.setVisibility(visible ? View.GONE : View.VISIBLE);
mRightSpacerLandscape.setVisibility(visible ? View.GONE : View.VISIBLE);
}
}
/** /**
* The pattern listener that responds according to a user confirming * The pattern listener that responds according to a user confirming
* an existing lock pattern. * an existing lock pattern.