Files
app_Settings/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
Antony Sargent 9ceb587ede Don't crash on null Intent in FingerprintEnrollFindSensor
During a run of the setup wizard, a tester one time encountered a case
where the 'Accept Legal terms' screen followed by the Security screen
showed for a second time after already confirming the pattern in the
Security screen. The logs showed a crash in
FingerprintEnrollFindSensor.onActivityResult which could only have
happened if it was called with a requestCode of CONFIRM_REQUEST and a
resultCode of RESULT_OK, but a null Intent.

This isn't an expected flow, and AFAIK we haven't been able to reproduce
the original problem, but it seems reasonable to at least not crash in
settings, so this CL defends against that crash by just calling finish()
in this case, which means the caller who started the
FingerprintEnrollFindSensor will see the default result code of
Activity.RESULT_CANCELLED.

Bug: 80099085
Test: make -j RunSettingsRoboTests
Change-Id: I94401eabe295e4d5396cf7d324fbf1902dc45f6d
2018-05-31 14:22:38 -07:00

237 lines
8.6 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.fingerprint;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.UserHandle;
import androidx.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.fingerprint.FingerprintEnrollSidecar.Listener;
import com.android.settings.password.ChooseLockSettingsHelper;
/**
* Activity explaining the fingerprint sensor location for fingerprint enrollment.
*/
public class FingerprintEnrollFindSensor extends FingerprintEnrollBase {
@VisibleForTesting
static final int CONFIRM_REQUEST = 1;
private static final int ENROLLING = 2;
public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
@Nullable
private FingerprintFindSensorAnimation mAnimation;
private boolean mLaunchedConfirmLock;
private FingerprintEnrollSidecar mSidecar;
private boolean mNextClicked;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentView());
Button skipButton = findViewById(R.id.skip_button);
skipButton.setOnClickListener(this);
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
if (savedInstanceState != null) {
mLaunchedConfirmLock = savedInstanceState.getBoolean(EXTRA_KEY_LAUNCHED_CONFIRM);
mToken = savedInstanceState.getByteArray(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
}
if (mToken == null && !mLaunchedConfirmLock) {
launchConfirmLock();
} else if (mToken != null) {
startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
}
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
if (animationView instanceof FingerprintFindSensorAnimation) {
mAnimation = (FingerprintFindSensorAnimation) animationView;
} else {
mAnimation = null;
}
}
protected int getContentView() {
return R.layout.fingerprint_enroll_find_sensor;
}
@Override
protected void onStart() {
super.onStart();
if (mAnimation != null) {
mAnimation.startAnimation();
}
}
private void startLookingForFingerprint() {
mSidecar = (FingerprintEnrollSidecar) getFragmentManager().findFragmentByTag(
FingerprintEnrollEnrolling.TAG_SIDECAR);
if (mSidecar == null) {
mSidecar = new FingerprintEnrollSidecar();
getFragmentManager().beginTransaction()
.add(mSidecar, FingerprintEnrollEnrolling.TAG_SIDECAR).commit();
}
mSidecar.setListener(new Listener() {
@Override
public void onEnrollmentProgressChange(int steps, int remaining) {
mNextClicked = true;
proceedToEnrolling(true /* cancelEnrollment */);
}
@Override
public void onEnrollmentHelp(CharSequence helpString) {
}
@Override
public void onEnrollmentError(int errMsgId, CharSequence errString) {
if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
mNextClicked = false;
proceedToEnrolling(false /* cancelEnrollment */);
}
}
});
}
@Override
protected void onStop() {
super.onStop();
if (mAnimation != null) {
mAnimation.pauseAnimation();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mAnimation != null) {
mAnimation.stopAnimation();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_KEY_LAUNCHED_CONFIRM, mLaunchedConfirmLock);
outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.skip_button:
onSkipButtonClick();
break;
default:
super.onClick(v);
}
}
protected void onSkipButtonClick() {
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;
}
}
getFragmentManager().beginTransaction().remove(mSidecar).commitAllowingStateLoss();
mSidecar = null;
startActivityForResult(getEnrollingIntent(), ENROLLING);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CONFIRM_REQUEST) {
if (resultCode == RESULT_OK && data != null) {
mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
startLookingForFingerprint();
} else {
finish();
}
} else if (requestCode == ENROLLING) {
if (resultCode == RESULT_FINISHED) {
setResult(RESULT_FINISHED);
finish();
} else if (resultCode == RESULT_SKIP) {
setResult(RESULT_SKIP);
finish();
} else if (resultCode == RESULT_TIMEOUT) {
setResult(RESULT_TIMEOUT);
finish();
} else {
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();
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void launchConfirmLock() {
long challenge = Utils.getFingerprintManagerOrNull(this).preEnroll();
ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this);
boolean launchedConfirmationActivity = false;
if (mUserId == UserHandle.USER_NULL) {
launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST,
getString(R.string.security_settings_fingerprint_preference_title),
null, null, challenge);
} else {
launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST,
getString(R.string.security_settings_fingerprint_preference_title),
null, null, challenge, mUserId);
}
if (!launchedConfirmationActivity) {
// This shouldn't happen, as we should only end up at this step if a lock thingy is
// already set.
finish();
} else {
mLaunchedConfirmLock = true;
}
}
@Override
public int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_FIND_SENSOR;
}
}