Files
app_Settings/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
Kevin Chyn 1bad80b36b Use lottie animation for fingerprint edu
The landscape layout can be removed now, since for UDFPS,
we do not use this page for the "find sensor" functionality anymore.
Instead, we show the edu animation.

Bug: 187460696
Test: manual

Change-Id: Ic2e15ecf73c42b8a0cea4ea8996b1b7dd2f3b4f2
2021-05-26 14:49:51 -07:00

292 lines
11 KiB
Java

/*
* 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.app.settings.SettingsEnums;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.Nullable;
import com.airbnb.lottie.LottieAnimationView;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import java.util.List;
/**
* Activity explaining the fingerprint sensor location for fingerprint enrollment.
*/
public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements
BiometricEnrollSidecar.Listener {
@Nullable
private FingerprintFindSensorAnimation mAnimation;
private FingerprintEnrollSidecar mSidecar;
private boolean mNextClicked;
private boolean mCanAssumeUdfps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
final List<FingerprintSensorPropertiesInternal> props =
fingerprintManager.getSensorPropertiesInternal();
mCanAssumeUdfps = props != null && props.size() == 1 && props.get(0).isAnyUdfpsType();
setContentView(getContentView());
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
.setListener(this::onSkipButtonClick)
.setButtonType(FooterButton.ButtonType.SKIP)
.setTheme(R.style.SudGlifButton_Secondary)
.build()
);
if (mCanAssumeUdfps) {
setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title);
setDescriptionText(R.string.security_settings_udfps_enroll_find_sensor_message);
mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_udfps_enroll_find_sensor_start_button)
.setListener(this::onStartButtonClick)
.setButtonType(FooterButton.ButtonType.NEXT)
.setTheme(R.style.SudGlifButton_Primary)
.build()
);
LottieAnimationView lottieAnimationView = findViewById(R.id.illustration_lottie);
AccessibilityManager am = getSystemService(AccessibilityManager.class);
if (am.isEnabled()) {
lottieAnimationView.setAnimation(R.raw.udfps_edu_a11y_lottie);
}
} else {
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message);
}
// This is an entry point for SetNewPasswordController, e.g.
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
final FingerprintManager fpm = getSystemService(FingerprintManager.class);
fpm.generateChallenge(mUserId, (sensorId, userId, challenge) -> {
mChallenge = challenge;
mSensorId = sensorId;
mToken = BiometricUtils.requestGatekeeperHat(this, getIntent(), mUserId, challenge);
// Put this into the intent. This is really just to work around the fact that the
// enrollment sidecar gets the HAT from the activity's intent, rather than having
// it passed in.
getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
startLookingForFingerprint();
});
} 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...");
}
mAnimation = null;
if (!mCanAssumeUdfps) {
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
if (animationView instanceof FingerprintFindSensorAnimation) {
mAnimation = (FingerprintFindSensorAnimation) animationView;
}
}
}
@Override
public void onBackPressed() {
stopLookingForFingerprint();
super.onBackPressed();
}
protected int getContentView() {
if (mCanAssumeUdfps) {
return R.layout.udfps_enroll_find_sensor_layout;
}
return R.layout.fingerprint_enroll_find_sensor;
}
@Override
protected void onStart() {
super.onStart();
if (mAnimation != null) {
mAnimation.startAnimation();
}
}
private void stopLookingForFingerprint() {
if (mSidecar != null) {
mSidecar.setListener(null);
mSidecar.cancelEnrollment();
getSupportFragmentManager()
.beginTransaction().remove(mSidecar).commitAllowingStateLoss();
mSidecar = null;
}
}
private void startLookingForFingerprint() {
if (mCanAssumeUdfps) {
// UDFPS devices use this screen as an educational screen. Users should tap the
// "Start" button to move to the next screen to begin enrollment.
return;
}
mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag(
FingerprintEnrollEnrolling.TAG_SIDECAR);
if (mSidecar == null) {
mSidecar = new FingerprintEnrollSidecar();
mSidecar.setEnrollReason(FingerprintManager.ENROLL_FIND_SENSOR);
getSupportFragmentManager().beginTransaction()
.add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR)
.commitAllowingStateLoss();
}
mSidecar.setListener(this);
}
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
mNextClicked = true;
proceedToEnrolling(true /* cancelEnrollment */);
}
@Override
public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
mNextClicked = false;
proceedToEnrolling(false /* cancelEnrollment */);
} else {
FingerprintErrorDialog.showErrorDialog(this, errMsgId);
}
}
@Override
protected void onStop() {
super.onStop();
if (mAnimation != null) {
mAnimation.pauseAnimation();
}
}
@Override
protected boolean shouldFinishWhenBackgrounded() {
return super.shouldFinishWhenBackgrounded() && !mNextClicked;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mAnimation != null) {
mAnimation.stopAnimation();
}
}
private void onStartButtonClick(View view) {
startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
}
protected void onSkipButtonClick(View view) {
stopLookingForFingerprint();
setResult(RESULT_SKIP);
finish();
}
private void proceedToEnrolling(boolean cancelEnrollment) {
if (mSidecar != null) {
if (cancelEnrollment) {
if (mSidecar.cancelEnrollment()) {
// Enrollment cancel requested. When the cancellation is successful,
// onEnrollmentError will be called with FINGERPRINT_ERROR_CANCELED, calling
// this again.
return;
}
}
getSupportFragmentManager().beginTransaction().remove(mSidecar).
commitAllowingStateLoss();
mSidecar = null;
startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CONFIRM_REQUEST) {
if (resultCode == RESULT_OK && data != null) {
throw new IllegalStateException("Pretty sure this is dead code");
/*
mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
startLookingForFingerprint();
*/
} else {
finish();
}
} else if (requestCode == ENROLL_REQUEST) {
switch (resultCode) {
case RESULT_FINISHED:
case RESULT_SKIP:
case RESULT_TIMEOUT:
setResult(resultCode);
finish();
break;
default:
FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
int enrolled = fpm.getEnrolledFingerprints().size();
int max = getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
if (enrolled >= max) {
finish();
} else {
// We came back from enrolling but it wasn't completed, start again.
startLookingForFingerprint();
}
break;
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public int getMetricsCategory() {
return SettingsEnums.FINGERPRINT_FIND_SENSOR;
}
}