Merge "[BiometricsV2] Rewrite Activity to Kotlin"
This commit is contained in:
committed by
Android (Google) Code Review
commit
aa3dbf52e2
@@ -1,637 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 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.biometrics2.ui.view;
|
|
||||||
|
|
||||||
import static androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
|
||||||
import static androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
|
||||||
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
|
|
||||||
|
|
||||||
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY;
|
|
||||||
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.ENROLLMENT_REQUEST_KEY;
|
|
||||||
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.USER_ID_KEY;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FingerprintEnrollFinishAction;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
|
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FingerprintEnrollIntroAction;
|
|
||||||
|
|
||||||
import android.annotation.StyleRes;
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.lifecycle.Observer;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.lifecycle.viewmodel.CreationExtras;
|
|
||||||
import androidx.lifecycle.viewmodel.MutableCreationExtras;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.Utils;
|
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
|
||||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
|
||||||
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory;
|
|
||||||
import com.android.settings.biometrics2.ui.model.CredentialModel;
|
|
||||||
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
|
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel;
|
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
|
||||||
|
|
||||||
import com.google.android.setupdesign.util.ThemeHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fingerprint enrollment activity implementation
|
|
||||||
*/
|
|
||||||
public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setupwizard activity
|
|
||||||
*/
|
|
||||||
public static class SetupActivity extends FingerprintEnrollmentActivity {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal activity for FingerprintSettings
|
|
||||||
*/
|
|
||||||
public static class InternalActivity extends FingerprintEnrollmentActivity {}
|
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
private static final String TAG = "FingerprintEnrollmentActivity";
|
|
||||||
|
|
||||||
private static final String INTRO_TAG = "intro";
|
|
||||||
private static final String FIND_SENSOR_TAG = "find-sensor";
|
|
||||||
private static final String ENROLLING_TAG = "enrolling";
|
|
||||||
private static final String FINISH_TAG = "finish";
|
|
||||||
private static final String SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog";
|
|
||||||
private static final String ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog";
|
|
||||||
|
|
||||||
protected static final int LAUNCH_CONFIRM_LOCK_ACTIVITY = 1;
|
|
||||||
|
|
||||||
// This flag is used for addBackStack(), we do not save it in ViewModel because it is just used
|
|
||||||
// during FragmentManager calls
|
|
||||||
private boolean mIsFirstFragmentAdded = false;
|
|
||||||
|
|
||||||
private ViewModelProvider mViewModelProvider;
|
|
||||||
private FingerprintEnrollmentViewModel mViewModel;
|
|
||||||
private AutoCredentialViewModel mAutoCredentialViewModel;
|
|
||||||
private final Observer<Integer> mIntroActionObserver = action -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mIntroActionObserver(" + action + ")");
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
onIntroAction(action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Observer<Integer> mFindSensorActionObserver = action -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mFindSensorActionObserver(" + action + ")");
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
onFindSensorAction(action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Observer<Integer> mEnrollingActionObserver = action -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mEnrollingActionObserver(" + action + ")");
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
onEnrollingAction(action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Observer<ErrorDialogData> mEnrollingErrorDialogObserver = data -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mEnrollingErrorDialogObserver(" + data + ")");
|
|
||||||
}
|
|
||||||
if (data != null) {
|
|
||||||
new FingerprintEnrollEnrollingErrorDialog().show(getSupportFragmentManager(),
|
|
||||||
ENROLLING_ERROR_DIALOG_TAG);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Observer<Integer> mEnrollingErrorDialogActionObserver = action -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mEnrollingErrorDialogActionObserver(" + action + ")");
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
onEnrollingErrorDialogAction(action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final Observer<Integer> mFinishActionObserver = action -> {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "mFinishActionObserver(" + action + ")");
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
onFinishAction(action);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final ActivityResultCallback<ActivityResult> mChooseLockResultCallback =
|
|
||||||
result -> onChooseOrConfirmLockResult(true /* isChooseLock */, result);
|
|
||||||
private final ActivityResultLauncher<Intent> mChooseLockLauncher =
|
|
||||||
registerForActivityResult(new StartActivityForResult(), mChooseLockResultCallback);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mViewModelProvider = new ViewModelProvider(this);
|
|
||||||
|
|
||||||
mViewModel = mViewModelProvider.get(FingerprintEnrollmentViewModel.class);
|
|
||||||
mViewModel.setSavedInstanceState(savedInstanceState);
|
|
||||||
|
|
||||||
mAutoCredentialViewModel = mViewModelProvider.get(AutoCredentialViewModel.class);
|
|
||||||
mAutoCredentialViewModel.setCredentialModel(savedInstanceState, getIntent());
|
|
||||||
|
|
||||||
// Theme
|
|
||||||
setTheme(mViewModel.getRequest().getTheme());
|
|
||||||
ThemeHelper.trySetDynamicColor(this);
|
|
||||||
getWindow().setStatusBarColor(android.graphics.Color.TRANSPARENT);
|
|
||||||
|
|
||||||
// fragment
|
|
||||||
setContentView(R.layout.biometric_enrollment_container);
|
|
||||||
|
|
||||||
final Fragment fragment = getSupportFragmentManager().findFragmentById(
|
|
||||||
R.id.fragment_container_view);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onCreate() has savedInstance:" + (savedInstanceState != null)
|
|
||||||
+ ", fragment:" + fragment);
|
|
||||||
}
|
|
||||||
if (fragment == null) {
|
|
||||||
checkCredential();
|
|
||||||
final EnrollmentRequest request = mViewModel.getRequest();
|
|
||||||
if (request.isSkipFindSensor()) {
|
|
||||||
startEnrollingFragment();
|
|
||||||
} else if (request.isSkipIntro()) {
|
|
||||||
startFindSensorFragment();
|
|
||||||
} else {
|
|
||||||
startIntroFragment();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String tag = fragment.getTag();
|
|
||||||
if (INTRO_TAG.equals(tag)) {
|
|
||||||
attachIntroViewModel();
|
|
||||||
} else if (FIND_SENSOR_TAG.equals(tag)) {
|
|
||||||
attachFindSensorViewModel();
|
|
||||||
attachIntroViewModel();
|
|
||||||
} else if (ENROLLING_TAG.equals(tag)) {
|
|
||||||
attachEnrollingViewModel();
|
|
||||||
attachFindSensorViewModel();
|
|
||||||
attachIntroViewModel();
|
|
||||||
} else if (FINISH_TAG.equals(tag)) {
|
|
||||||
attachFinishViewModel();
|
|
||||||
attachFindSensorViewModel();
|
|
||||||
attachIntroViewModel();
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "fragment tag " + tag + " not found");
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// observe LiveData
|
|
||||||
mViewModel.getSetResultLiveData().observe(this, this::onSetActivityResult);
|
|
||||||
|
|
||||||
mAutoCredentialViewModel.getGenerateChallengeFailedLiveData().observe(this,
|
|
||||||
this::onGenerateChallengeFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startFragment(@NonNull Class<? extends Fragment> fragmentClass,
|
|
||||||
@NonNull String tag) {
|
|
||||||
if (!mIsFirstFragmentAdded) {
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.setReorderingAllowed(true)
|
|
||||||
.replace(R.id.fragment_container_view, fragmentClass, null, tag)
|
|
||||||
.commit();
|
|
||||||
mIsFirstFragmentAdded = true;
|
|
||||||
} else {
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.setReorderingAllowed(true)
|
|
||||||
.setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_open_exit,
|
|
||||||
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_close_exit)
|
|
||||||
.replace(R.id.fragment_container_view, fragmentClass, null, tag)
|
|
||||||
.addToBackStack(tag)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startIntroFragment() {
|
|
||||||
attachIntroViewModel();
|
|
||||||
startFragment(FingerprintEnrollIntroFragment.class, INTRO_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attachIntroViewModel() {
|
|
||||||
final EnrollmentRequest request = mViewModel.getRequest();
|
|
||||||
if (request.isSkipIntro() || request.isSkipFindSensor()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final FingerprintEnrollIntroViewModel introViewModel =
|
|
||||||
mViewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
|
||||||
|
|
||||||
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
|
|
||||||
// recreate, like press 'Agree' then press 'back' in FingerprintEnrollFindSensor activity.
|
|
||||||
introViewModel.clearActionLiveData();
|
|
||||||
introViewModel.getActionLiveData().observe(this, mIntroActionObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to make sure token is valid before entering find sensor page
|
|
||||||
private void startFindSensorFragment() {
|
|
||||||
// Always setToken into progressViewModel even it is not necessary action for UDFPS
|
|
||||||
mViewModelProvider.get(FingerprintEnrollProgressViewModel.class)
|
|
||||||
.setToken(mAutoCredentialViewModel.getToken());
|
|
||||||
|
|
||||||
attachFindSensorViewModel();
|
|
||||||
|
|
||||||
final Class<? extends Fragment> fragmentClass;
|
|
||||||
if (mViewModel.canAssumeUdfps()) {
|
|
||||||
fragmentClass = FingerprintEnrollFindUdfpsFragment.class;
|
|
||||||
} else if (mViewModel.canAssumeSfps()) {
|
|
||||||
fragmentClass = FingerprintEnrollFindSfpsFragment.class;
|
|
||||||
} else {
|
|
||||||
fragmentClass = FingerprintEnrollFindRfpsFragment.class;
|
|
||||||
}
|
|
||||||
startFragment(fragmentClass, FIND_SENSOR_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attachFindSensorViewModel() {
|
|
||||||
if (mViewModel.getRequest().isSkipFindSensor()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final FingerprintEnrollFindSensorViewModel findSensorViewModel =
|
|
||||||
mViewModelProvider.get(FingerprintEnrollFindSensorViewModel.class);
|
|
||||||
|
|
||||||
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
|
|
||||||
// recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling activity.
|
|
||||||
findSensorViewModel.clearActionLiveData();
|
|
||||||
findSensorViewModel.getActionLiveData().observe(this, mFindSensorActionObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startEnrollingFragment() {
|
|
||||||
// Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
|
|
||||||
mViewModelProvider.get(FingerprintEnrollProgressViewModel.class)
|
|
||||||
.setToken(mAutoCredentialViewModel.getToken());
|
|
||||||
|
|
||||||
attachEnrollingViewModel();
|
|
||||||
|
|
||||||
final Class<? extends Fragment> fragmentClass;
|
|
||||||
if (mViewModel.canAssumeUdfps()) {
|
|
||||||
fragmentClass = FingerprintEnrollEnrollingUdfpsFragment.class;
|
|
||||||
} else if (mViewModel.canAssumeSfps()) {
|
|
||||||
fragmentClass = FingerprintEnrollEnrollingSfpsFragment.class;
|
|
||||||
} else {
|
|
||||||
fragmentClass = FingerprintEnrollEnrollingRfpsFragment.class;
|
|
||||||
}
|
|
||||||
startFragment(fragmentClass, ENROLLING_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attachEnrollingViewModel() {
|
|
||||||
final FingerprintEnrollEnrollingViewModel enrollingViewModel =
|
|
||||||
mViewModelProvider.get(FingerprintEnrollEnrollingViewModel.class);
|
|
||||||
enrollingViewModel.clearActionLiveData();
|
|
||||||
enrollingViewModel.getActionLiveData().observe(this, mEnrollingActionObserver);
|
|
||||||
enrollingViewModel.getErrorDialogLiveData().observe(this, mEnrollingErrorDialogObserver);
|
|
||||||
enrollingViewModel.getErrorDialogActionLiveData().observe(this,
|
|
||||||
mEnrollingErrorDialogActionObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startFinishFragment() {
|
|
||||||
mViewModel.setIsNewFingerprintAdded();
|
|
||||||
attachFinishViewModel();
|
|
||||||
|
|
||||||
if (mViewModel.getRequest().isSkipFindSensor()) {
|
|
||||||
// Set page to Finish
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.setReorderingAllowed(true)
|
|
||||||
.setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_open_exit,
|
|
||||||
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_close_exit)
|
|
||||||
.replace(R.id.fragment_container_view, FingerprintEnrollFinishFragment.class,
|
|
||||||
null, FINISH_TAG)
|
|
||||||
.commit();
|
|
||||||
} else {
|
|
||||||
// Remove Enrolling page
|
|
||||||
getSupportFragmentManager().popBackStack();
|
|
||||||
|
|
||||||
// Remove old Finish page if any
|
|
||||||
if (getSupportFragmentManager().findFragmentByTag(FINISH_TAG) != null) {
|
|
||||||
getSupportFragmentManager().popBackStack(FINISH_TAG, POP_BACK_STACK_INCLUSIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove FindSensor page if maxEnrolled
|
|
||||||
if (mViewModel.isMaxEnrolledReached(mAutoCredentialViewModel.getUserId())
|
|
||||||
&& getSupportFragmentManager().findFragmentByTag(FIND_SENSOR_TAG) != null) {
|
|
||||||
getSupportFragmentManager().popBackStack(FIND_SENSOR_TAG, POP_BACK_STACK_INCLUSIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Finish page
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.setReorderingAllowed(true)
|
|
||||||
.setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_open_exit,
|
|
||||||
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
|
||||||
R.anim.shared_x_axis_activity_close_exit)
|
|
||||||
.replace(R.id.fragment_container_view, FingerprintEnrollFinishFragment.class,
|
|
||||||
null, FINISH_TAG)
|
|
||||||
.addToBackStack(FINISH_TAG)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attachFinishViewModel() {
|
|
||||||
final FingerprintEnrollFinishViewModel viewModel =
|
|
||||||
mViewModelProvider.get(FingerprintEnrollFinishViewModel.class);
|
|
||||||
viewModel.clearActionLiveData();
|
|
||||||
viewModel.getActionLiveData().observe(this, mFinishActionObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onGenerateChallengeFailed(@NonNull Boolean ignoredBoolean) {
|
|
||||||
onSetActivityResult(new ActivityResult(RESULT_CANCELED, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSetActivityResult(@NonNull ActivityResult result) {
|
|
||||||
final Bundle challengeExtras = mAutoCredentialViewModel.createGeneratingChallengeExtras();
|
|
||||||
final ActivityResult overrideResult = mViewModel.getOverrideActivityResult(
|
|
||||||
result, challengeExtras);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onSetActivityResult(" + result + "), override:" + overrideResult
|
|
||||||
+ ") challengeExtras:" + challengeExtras);
|
|
||||||
}
|
|
||||||
setResult(overrideResult.getResultCode(), overrideResult.getData());
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkCredential() {
|
|
||||||
switch (mAutoCredentialViewModel.checkCredential()) {
|
|
||||||
case CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK: {
|
|
||||||
final Intent intent = mAutoCredentialViewModel.createChooseLockIntent(this,
|
|
||||||
mViewModel.getRequest().isSuw(), mViewModel.getRequest().getSuwExtras());
|
|
||||||
if (!mViewModel.isWaitingActivityResult().compareAndSet(false, true)) {
|
|
||||||
Log.w(TAG, "chooseLock, fail to set isWaiting flag to true");
|
|
||||||
}
|
|
||||||
mChooseLockLauncher.launch(intent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK: {
|
|
||||||
final boolean launched = mAutoCredentialViewModel.createConfirmLockLauncher(
|
|
||||||
this,
|
|
||||||
LAUNCH_CONFIRM_LOCK_ACTIVITY,
|
|
||||||
getString(R.string.security_settings_fingerprint_preference_title)
|
|
||||||
).launch();
|
|
||||||
if (!launched) {
|
|
||||||
// This shouldn't happen, as we should only end up at this step if a lock thingy
|
|
||||||
// is already set.
|
|
||||||
Log.e(TAG, "confirmLock, launched is true");
|
|
||||||
finish();
|
|
||||||
} else if (!mViewModel.isWaitingActivityResult().compareAndSet(false, true)) {
|
|
||||||
Log.w(TAG, "confirmLock, fail to set isWaiting flag to true");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case CREDENTIAL_VALID:
|
|
||||||
case CREDENTIAL_IS_GENERATING_CHALLENGE: {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onChooseOrConfirmLockResult(boolean isChooseLock,
|
|
||||||
@NonNull ActivityResult activityResult) {
|
|
||||||
if (!mViewModel.isWaitingActivityResult().compareAndSet(true, false)) {
|
|
||||||
Log.w(TAG, "isChooseLock:" + isChooseLock + ", fail to unset waiting flag");
|
|
||||||
}
|
|
||||||
if (mAutoCredentialViewModel.checkNewCredentialFromActivityResult(
|
|
||||||
isChooseLock, activityResult)) {
|
|
||||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
|
||||||
} else {
|
|
||||||
onSetActivityResult(activityResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onIntroAction(@FingerprintEnrollIntroAction int action) {
|
|
||||||
switch (action) {
|
|
||||||
case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
|
|
||||||
onSetActivityResult(
|
|
||||||
new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL: {
|
|
||||||
onSetActivityResult(
|
|
||||||
new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL: {
|
|
||||||
startFindSensorFragment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onFindSensorAction(@FingerprintEnrollFindSensorAction int action) {
|
|
||||||
switch (action) {
|
|
||||||
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP: {
|
|
||||||
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG: {
|
|
||||||
new SkipSetupFindFpsDialog().show(getSupportFragmentManager(),
|
|
||||||
SKIP_SETUP_FIND_FPS_DIALOG_TAG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START: {
|
|
||||||
startEnrollingFragment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onEnrollingAction(@FingerprintEnrollEnrollingAction int action) {
|
|
||||||
switch (action) {
|
|
||||||
case FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE: {
|
|
||||||
startFinishFragment();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP: {
|
|
||||||
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG: {
|
|
||||||
new FingerprintEnrollEnrollingIconTouchDialog().show(getSupportFragmentManager(),
|
|
||||||
SKIP_SETUP_FIND_FPS_DIALOG_TAG);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED: {
|
|
||||||
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
|
|
||||||
getSupportFragmentManager().popBackStack();
|
|
||||||
} else {
|
|
||||||
onSetActivityResult(new ActivityResult(RESULT_CANCELED, null));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onEnrollingErrorDialogAction(@FingerprintErrorDialogAction int action) {
|
|
||||||
switch (action) {
|
|
||||||
case FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH:
|
|
||||||
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null));
|
|
||||||
break;
|
|
||||||
case FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT:
|
|
||||||
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onFinishAction(@FingerprintEnrollFinishAction int action) {
|
|
||||||
switch (action) {
|
|
||||||
case FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK: {
|
|
||||||
startEnrollingFragment();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK: {
|
|
||||||
final Intent data;
|
|
||||||
if (mViewModel.getRequest().isSuw()) {
|
|
||||||
data = new Intent();
|
|
||||||
data.putExtras(mViewModel.getSuwFingerprintCountExtra(
|
|
||||||
mAutoCredentialViewModel.getUserId()));
|
|
||||||
} else {
|
|
||||||
data = null;
|
|
||||||
}
|
|
||||||
onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mViewModel.checkFinishActivityDuringOnPause(isFinishing(), isChangingConfigurations());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
mViewModel.updateFingerprintSuggestionEnableState(mAutoCredentialViewModel.getUserId());
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid, boolean first) {
|
|
||||||
theme.applyStyle(R.style.SetupWizardPartnerResource, true);
|
|
||||||
super.onApplyThemeResource(theme, resid, first);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
|
||||||
if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {
|
|
||||||
onChooseOrConfirmLockResult(false, new ActivityResult(resultCode, data));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public CreationExtras getDefaultViewModelCreationExtras() {
|
|
||||||
final Application application =
|
|
||||||
super.getDefaultViewModelCreationExtras().get(APPLICATION_KEY);
|
|
||||||
final MutableCreationExtras ret = new MutableCreationExtras();
|
|
||||||
ret.set(APPLICATION_KEY, application);
|
|
||||||
|
|
||||||
final FingerprintRepository repository = FeatureFactory.getFactory(application)
|
|
||||||
.getBiometricsRepositoryProvider().getFingerprintRepository(application);
|
|
||||||
ret.set(CHALLENGE_GENERATOR_KEY, new FingerprintChallengeGenerator(repository));
|
|
||||||
|
|
||||||
ret.set(ENROLLMENT_REQUEST_KEY, new EnrollmentRequest(getIntent(), getApplicationContext(),
|
|
||||||
this instanceof SetupActivity));
|
|
||||||
|
|
||||||
Bundle extras = getIntent().getExtras();
|
|
||||||
final CredentialModel credentialModel = new CredentialModel(extras,
|
|
||||||
SystemClock.elapsedRealtimeClock());
|
|
||||||
ret.set(USER_ID_KEY, credentialModel.getUserId());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
|
|
||||||
return new BiometricsViewModelFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow();
|
|
||||||
getWindow().setStatusBarColor(getBackgroundColor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ColorInt
|
|
||||||
private int getBackgroundColor() {
|
|
||||||
final ColorStateList stateList = Utils.getColorAttr(this, android.R.attr.windowBackground);
|
|
||||||
return stateList != null ? stateList.getDefaultColor() : Color.TRANSPARENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
|
||||||
mViewModelProvider.get(DeviceFoldedViewModel.class).onConfigurationChanged(newConfig);
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
mViewModel.onSaveInstanceState(outState);
|
|
||||||
mAutoCredentialViewModel.onSaveInstanceState(outState);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,644 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.biometrics2.ui.view
|
||||||
|
|
||||||
|
import android.annotation.StyleRes
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.content.res.Resources.Theme
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.SystemClock
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.ActivityResultCallback
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewmodel.CreationExtras
|
||||||
|
import androidx.lifecycle.viewmodel.MutableCreationExtras
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.Utils
|
||||||
|
import com.android.settings.biometrics.BiometricEnrollBase
|
||||||
|
import com.android.settings.biometrics2.data.repository.FingerprintRepository
|
||||||
|
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory
|
||||||
|
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY
|
||||||
|
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.ENROLLMENT_REQUEST_KEY
|
||||||
|
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.USER_ID_KEY
|
||||||
|
import com.android.settings.biometrics2.ui.model.CredentialModel
|
||||||
|
import com.android.settings.biometrics2.ui.model.EnrollmentRequest
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FingerprintEnrollFinishAction
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FingerprintEnrollIntroAction
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
|
||||||
|
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel
|
||||||
|
import com.android.settings.overlay.FeatureFactory
|
||||||
|
import com.google.android.setupdesign.util.ThemeHelper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fingerprint enrollment activity implementation
|
||||||
|
*/
|
||||||
|
open class FingerprintEnrollmentActivity : FragmentActivity() {
|
||||||
|
/** SetupWizard activity*/
|
||||||
|
class SetupActivity : FingerprintEnrollmentActivity()
|
||||||
|
|
||||||
|
/** Internal activity for FingerprintSettings */
|
||||||
|
class InternalActivity : FingerprintEnrollmentActivity()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag is used for addBackStack(), we do not save it in ViewModel because it is just used
|
||||||
|
* during FragmentManager calls
|
||||||
|
*/
|
||||||
|
private var isFirstFragmentAdded = false
|
||||||
|
|
||||||
|
private val viewModelProvider: ViewModelProvider by lazy {
|
||||||
|
ViewModelProvider(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val viewModel: FingerprintEnrollmentViewModel by lazy {
|
||||||
|
viewModelProvider[FingerprintEnrollmentViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
|
private val autoCredentialViewModel: AutoCredentialViewModel by lazy {
|
||||||
|
viewModelProvider[AutoCredentialViewModel::class.java]
|
||||||
|
}
|
||||||
|
|
||||||
|
private val introActionObserver: Observer<Int> = Observer<Int> { action ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "introActionObserver($action)")
|
||||||
|
}
|
||||||
|
action?.let { onIntroAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val findSensorActionObserver: Observer<Int> = Observer<Int> { action ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "findSensorActionObserver($action)")
|
||||||
|
}
|
||||||
|
action?.let { onFindSensorAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enrollingActionObserver: Observer<Int> = Observer<Int> { action ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "enrollingActionObserver($action)")
|
||||||
|
}
|
||||||
|
action?.let { onEnrollingAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enrollingErrorDialogObserver: Observer<ErrorDialogData> =
|
||||||
|
Observer<ErrorDialogData> { data ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "enrollingErrorDialogObserver($data)")
|
||||||
|
}
|
||||||
|
data?.let {
|
||||||
|
FingerprintEnrollEnrollingErrorDialog().show(
|
||||||
|
supportFragmentManager,
|
||||||
|
ENROLLING_ERROR_DIALOG_TAG
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enrollingErrorDialogActionObserver: Observer<Int> = Observer<Int> { action ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "enrollingErrorDialogActionObserver($action)")
|
||||||
|
}
|
||||||
|
action?.let { onEnrollingErrorDialogAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val finishActionObserver: Observer<Int> = Observer<Int> { action ->
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "finishActionObserver($action)")
|
||||||
|
}
|
||||||
|
action?.let { onFinishAction(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val chooseLockResultCallback: ActivityResultCallback<ActivityResult> =
|
||||||
|
ActivityResultCallback { result ->
|
||||||
|
onChooseOrConfirmLockResult(true /* isChooseLock */, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val chooseLockLauncher: ActivityResultLauncher<Intent> =
|
||||||
|
registerForActivityResult(StartActivityForResult(), chooseLockResultCallback)
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
viewModel.setSavedInstanceState(savedInstanceState)
|
||||||
|
autoCredentialViewModel.setCredentialModel(savedInstanceState, intent)
|
||||||
|
|
||||||
|
// Theme
|
||||||
|
setTheme(viewModel.request.theme)
|
||||||
|
ThemeHelper.trySetDynamicColor(this)
|
||||||
|
window.statusBarColor = Color.TRANSPARENT
|
||||||
|
|
||||||
|
// fragment
|
||||||
|
setContentView(R.layout.biometric_enrollment_container)
|
||||||
|
val fragment: Fragment? = supportFragmentManager.findFragmentById(
|
||||||
|
R.id.fragment_container_view
|
||||||
|
)
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG, "onCreate() has savedInstance:" + (savedInstanceState != null)
|
||||||
|
+ ", fragment:" + fragment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (fragment == null) {
|
||||||
|
checkCredential()
|
||||||
|
val request: EnrollmentRequest = viewModel.getRequest()
|
||||||
|
if (request.isSkipFindSensor) {
|
||||||
|
startEnrollingFragment()
|
||||||
|
} else if (request.isSkipIntro) {
|
||||||
|
startFindSensorFragment()
|
||||||
|
} else {
|
||||||
|
startIntroFragment()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val tag: String? = fragment.tag
|
||||||
|
if (INTRO_TAG == tag) {
|
||||||
|
attachIntroViewModel()
|
||||||
|
} else if (FIND_SENSOR_TAG == tag) {
|
||||||
|
attachFindSensorViewModel()
|
||||||
|
attachIntroViewModel()
|
||||||
|
} else if (ENROLLING_TAG == tag) {
|
||||||
|
attachEnrollingViewModel()
|
||||||
|
attachFindSensorViewModel()
|
||||||
|
attachIntroViewModel()
|
||||||
|
} else if (FINISH_TAG == tag) {
|
||||||
|
attachFinishViewModel()
|
||||||
|
attachFindSensorViewModel()
|
||||||
|
attachIntroViewModel()
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "fragment tag $tag not found")
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// observe LiveData
|
||||||
|
viewModel.setResultLiveData.observe(this) {
|
||||||
|
result: ActivityResult -> onSetActivityResult(result)
|
||||||
|
}
|
||||||
|
autoCredentialViewModel.generateChallengeFailedLiveData.observe(this) {
|
||||||
|
_: Boolean -> onGenerateChallengeFailed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startFragment(fragmentClass: Class<out Fragment>, tag: String) {
|
||||||
|
if (!isFirstFragmentAdded) {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.setReorderingAllowed(true)
|
||||||
|
.replace(R.id.fragment_container_view, fragmentClass, null, tag)
|
||||||
|
.commit()
|
||||||
|
isFirstFragmentAdded = true
|
||||||
|
} else {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.setReorderingAllowed(true)
|
||||||
|
.setCustomAnimations(
|
||||||
|
R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_open_exit,
|
||||||
|
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_close_exit
|
||||||
|
)
|
||||||
|
.replace(R.id.fragment_container_view, fragmentClass, null, tag)
|
||||||
|
.addToBackStack(tag)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startIntroFragment() {
|
||||||
|
attachIntroViewModel()
|
||||||
|
startFragment(FingerprintEnrollIntroFragment::class.java, INTRO_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachIntroViewModel() {
|
||||||
|
val request: EnrollmentRequest = viewModel.request
|
||||||
|
if (request.isSkipIntro || request.isSkipFindSensor) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viewModelProvider[FingerprintEnrollIntroViewModel::class.java].let {
|
||||||
|
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
|
||||||
|
// recreate, like press 'Agree' then press 'back' in FingerprintEnrollFindSensor
|
||||||
|
// activity.
|
||||||
|
it.clearActionLiveData()
|
||||||
|
it.actionLiveData.observe(this, introActionObserver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to make sure token is valid before entering find sensor page
|
||||||
|
private fun startFindSensorFragment() {
|
||||||
|
// Always setToken into progressViewModel even it is not necessary action for UDFPS
|
||||||
|
viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
|
||||||
|
.setToken(autoCredentialViewModel.token)
|
||||||
|
attachFindSensorViewModel()
|
||||||
|
val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps()) {
|
||||||
|
FingerprintEnrollFindUdfpsFragment::class.java
|
||||||
|
} else if (viewModel.canAssumeSfps()) {
|
||||||
|
FingerprintEnrollFindSfpsFragment::class.java
|
||||||
|
} else {
|
||||||
|
FingerprintEnrollFindRfpsFragment::class.java
|
||||||
|
}
|
||||||
|
startFragment(fragmentClass, FIND_SENSOR_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachFindSensorViewModel() {
|
||||||
|
if (viewModel.request.isSkipFindSensor) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java].let {
|
||||||
|
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
|
||||||
|
// recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling
|
||||||
|
// activity.
|
||||||
|
it.clearActionLiveData()
|
||||||
|
it.actionLiveData.observe(this, findSensorActionObserver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startEnrollingFragment() {
|
||||||
|
// Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
|
||||||
|
viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
|
||||||
|
.setToken(autoCredentialViewModel.token)
|
||||||
|
attachEnrollingViewModel()
|
||||||
|
val fragmentClass: Class<out Fragment> = if (viewModel.canAssumeUdfps()) {
|
||||||
|
FingerprintEnrollEnrollingUdfpsFragment::class.java
|
||||||
|
} else if (viewModel.canAssumeSfps()) {
|
||||||
|
FingerprintEnrollEnrollingSfpsFragment::class.java
|
||||||
|
} else {
|
||||||
|
FingerprintEnrollEnrollingRfpsFragment::class.java
|
||||||
|
}
|
||||||
|
startFragment(fragmentClass, ENROLLING_TAG)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachEnrollingViewModel() {
|
||||||
|
viewModelProvider[FingerprintEnrollEnrollingViewModel::class.java].let {
|
||||||
|
it.clearActionLiveData()
|
||||||
|
it.actionLiveData.observe(this, enrollingActionObserver)
|
||||||
|
it.errorDialogLiveData.observe(this, enrollingErrorDialogObserver)
|
||||||
|
it.errorDialogActionLiveData.observe(
|
||||||
|
this,
|
||||||
|
enrollingErrorDialogActionObserver
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startFinishFragment() {
|
||||||
|
viewModel.setIsNewFingerprintAdded()
|
||||||
|
attachFinishViewModel()
|
||||||
|
if (viewModel.request.isSkipFindSensor) {
|
||||||
|
// Set page to Finish
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.setReorderingAllowed(true)
|
||||||
|
.setCustomAnimations(
|
||||||
|
R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_open_exit,
|
||||||
|
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_close_exit
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
R.id.fragment_container_view,
|
||||||
|
FingerprintEnrollFinishFragment::class.java,
|
||||||
|
null,
|
||||||
|
FINISH_TAG
|
||||||
|
)
|
||||||
|
.commit()
|
||||||
|
} else {
|
||||||
|
// Remove Enrolling page
|
||||||
|
supportFragmentManager.popBackStack()
|
||||||
|
|
||||||
|
// Remove old Finish page if any
|
||||||
|
if (supportFragmentManager.findFragmentByTag(FINISH_TAG) != null) {
|
||||||
|
supportFragmentManager.popBackStack(FINISH_TAG, POP_BACK_STACK_INCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove FindSensor page if maxEnrolled
|
||||||
|
if (viewModel.isMaxEnrolledReached(autoCredentialViewModel.userId)
|
||||||
|
&& supportFragmentManager.findFragmentByTag(FIND_SENSOR_TAG) != null
|
||||||
|
) {
|
||||||
|
supportFragmentManager.popBackStack(FIND_SENSOR_TAG, POP_BACK_STACK_INCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Finish page
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.setReorderingAllowed(true)
|
||||||
|
.setCustomAnimations(
|
||||||
|
R.anim.shared_x_axis_activity_open_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_open_exit,
|
||||||
|
R.anim.shared_x_axis_activity_close_enter_dynamic_color,
|
||||||
|
R.anim.shared_x_axis_activity_close_exit
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
R.id.fragment_container_view,
|
||||||
|
FingerprintEnrollFinishFragment::class.java,
|
||||||
|
null,
|
||||||
|
FINISH_TAG
|
||||||
|
)
|
||||||
|
.addToBackStack(FINISH_TAG)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachFinishViewModel() {
|
||||||
|
viewModelProvider[FingerprintEnrollFinishViewModel::class.java].let {
|
||||||
|
it.clearActionLiveData()
|
||||||
|
it.actionLiveData.observe(this, finishActionObserver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onGenerateChallengeFailed() {
|
||||||
|
onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSetActivityResult(result: ActivityResult) {
|
||||||
|
val challengeExtras: Bundle? = autoCredentialViewModel.createGeneratingChallengeExtras()
|
||||||
|
val overrideResult: ActivityResult = viewModel.getOverrideActivityResult(
|
||||||
|
result, challengeExtras
|
||||||
|
)
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(
|
||||||
|
TAG, "onSetActivityResult(" + result + "), override:" + overrideResult
|
||||||
|
+ ") challengeExtras:" + challengeExtras
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setResult(overrideResult.resultCode, overrideResult.data)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkCredential() {
|
||||||
|
when (autoCredentialViewModel.checkCredential()) {
|
||||||
|
CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK -> {
|
||||||
|
val intent: Intent = autoCredentialViewModel.createChooseLockIntent(
|
||||||
|
this,
|
||||||
|
viewModel.request.isSuw,
|
||||||
|
viewModel.request.suwExtras
|
||||||
|
)
|
||||||
|
if (!viewModel.isWaitingActivityResult().compareAndSet(false, true)) {
|
||||||
|
Log.w(TAG, "chooseLock, fail to set isWaiting flag to true")
|
||||||
|
}
|
||||||
|
chooseLockLauncher.launch(intent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK -> {
|
||||||
|
val launched: Boolean = autoCredentialViewModel.createConfirmLockLauncher(
|
||||||
|
this,
|
||||||
|
LAUNCH_CONFIRM_LOCK_ACTIVITY,
|
||||||
|
getString(R.string.security_settings_fingerprint_preference_title)
|
||||||
|
).launch()
|
||||||
|
if (!launched) {
|
||||||
|
// This shouldn't happen, as we should only end up at this step if a lock thingy
|
||||||
|
// is already set.
|
||||||
|
Log.e(TAG, "confirmLock, launched is true")
|
||||||
|
finish()
|
||||||
|
} else if (!viewModel.isWaitingActivityResult().compareAndSet(false, true)) {
|
||||||
|
Log.w(TAG, "confirmLock, fail to set isWaiting flag to true")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CREDENTIAL_VALID,
|
||||||
|
CREDENTIAL_IS_GENERATING_CHALLENGE -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onChooseOrConfirmLockResult(isChooseLock: Boolean, activityResult: ActivityResult) {
|
||||||
|
if (!viewModel.isWaitingActivityResult().compareAndSet(true, false)) {
|
||||||
|
Log.w(TAG, "isChooseLock:$isChooseLock, fail to unset waiting flag")
|
||||||
|
}
|
||||||
|
if (autoCredentialViewModel.checkNewCredentialFromActivityResult(
|
||||||
|
isChooseLock, activityResult
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out)
|
||||||
|
} else {
|
||||||
|
onSetActivityResult(activityResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onIntroAction(@FingerprintEnrollIntroAction action: Int) {
|
||||||
|
when (action) {
|
||||||
|
FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH -> {
|
||||||
|
onSetActivityResult(
|
||||||
|
ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL -> {
|
||||||
|
onSetActivityResult(
|
||||||
|
ActivityResult(BiometricEnrollBase.RESULT_SKIP, null)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL -> {
|
||||||
|
startFindSensorFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFindSensorAction(@FingerprintEnrollFindSensorAction action: Int) {
|
||||||
|
when (action) {
|
||||||
|
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP -> {
|
||||||
|
onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG -> {
|
||||||
|
SkipSetupFindFpsDialog().show(
|
||||||
|
supportFragmentManager,
|
||||||
|
SKIP_SETUP_FIND_FPS_DIALOG_TAG
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START -> {
|
||||||
|
startEnrollingFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onEnrollingAction(@FingerprintEnrollEnrollingAction action: Int) {
|
||||||
|
when (action) {
|
||||||
|
FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE -> {
|
||||||
|
startFinishFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP -> {
|
||||||
|
onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG -> {
|
||||||
|
FingerprintEnrollEnrollingIconTouchDialog().show(
|
||||||
|
supportFragmentManager,
|
||||||
|
SKIP_SETUP_FIND_FPS_DIALOG_TAG
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED -> {
|
||||||
|
if (supportFragmentManager.backStackEntryCount > 0) {
|
||||||
|
supportFragmentManager.popBackStack()
|
||||||
|
} else {
|
||||||
|
onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onEnrollingErrorDialogAction(@FingerprintErrorDialogAction action: Int) {
|
||||||
|
when (action) {
|
||||||
|
FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH -> onSetActivityResult(
|
||||||
|
ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT -> onSetActivityResult(
|
||||||
|
ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onFinishAction(@FingerprintEnrollFinishAction action: Int) {
|
||||||
|
when (action) {
|
||||||
|
FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK -> {
|
||||||
|
startEnrollingFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK -> {
|
||||||
|
val data: Intent? = if (viewModel.request.isSuw) {
|
||||||
|
Intent().also {
|
||||||
|
it.putExtras(
|
||||||
|
viewModel.getSuwFingerprintCountExtra(
|
||||||
|
autoCredentialViewModel.userId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_FINISHED, data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
viewModel.checkFinishActivityDuringOnPause(isFinishing, isChangingConfigurations)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
viewModel.updateFingerprintSuggestionEnableState(autoCredentialViewModel.userId)
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onApplyThemeResource(theme: Theme, @StyleRes resid: Int, first: Boolean) {
|
||||||
|
theme.applyStyle(R.style.SetupWizardPartnerResource, true)
|
||||||
|
super.onApplyThemeResource(theme, resid, first)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {
|
||||||
|
onChooseOrConfirmLockResult(false, ActivityResult(resultCode, data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val defaultViewModelCreationExtras: CreationExtras
|
||||||
|
get() {
|
||||||
|
val fingerprintRepository = FeatureFactory
|
||||||
|
.getFactory(application)
|
||||||
|
.biometricsRepositoryProvider
|
||||||
|
.getFingerprintRepository(application)!!
|
||||||
|
val credentialModel = CredentialModel(intent.extras, SystemClock.elapsedRealtimeClock())
|
||||||
|
|
||||||
|
return MutableCreationExtras(super.defaultViewModelCreationExtras).also {
|
||||||
|
it[CHALLENGE_GENERATOR_KEY] = FingerprintChallengeGenerator(fingerprintRepository)
|
||||||
|
it[ENROLLMENT_REQUEST_KEY] =
|
||||||
|
EnrollmentRequest(intent, applicationContext, this is SetupActivity)
|
||||||
|
it[USER_ID_KEY] = credentialModel.userId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val defaultViewModelProviderFactory: ViewModelProvider.Factory
|
||||||
|
get() = BiometricsViewModelFactory()
|
||||||
|
|
||||||
|
override fun onAttachedToWindow() {
|
||||||
|
super.onAttachedToWindow()
|
||||||
|
window.statusBarColor = backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:ColorInt
|
||||||
|
private val backgroundColor: Int
|
||||||
|
get() {
|
||||||
|
val stateList: ColorStateList? =
|
||||||
|
Utils.getColorAttr(this, android.R.attr.windowBackground)
|
||||||
|
return stateList?.defaultColor ?: Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
viewModelProvider[DeviceFoldedViewModel::class.java].onConfigurationChanged(newConfig)
|
||||||
|
super.onConfigurationChanged(newConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
viewModel.onSaveInstanceState(outState)
|
||||||
|
autoCredentialViewModel.onSaveInstanceState(outState)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DEBUG = false
|
||||||
|
private const val TAG = "FingerprintEnrollmentActivity"
|
||||||
|
private const val INTRO_TAG = "intro"
|
||||||
|
private const val FIND_SENSOR_TAG = "find-sensor"
|
||||||
|
private const val ENROLLING_TAG = "enrolling"
|
||||||
|
private const val FINISH_TAG = "finish"
|
||||||
|
private const val SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog"
|
||||||
|
private const val ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog"
|
||||||
|
protected const val LAUNCH_CONFIRM_LOCK_ACTIVITY = 1
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,10 @@ android_test {
|
|||||||
platform_apis: true,
|
platform_apis: true,
|
||||||
certificate: "platform",
|
certificate: "platform",
|
||||||
test_suites: ["device-tests"],
|
test_suites: ["device-tests"],
|
||||||
srcs: ["src/**/*.java"],
|
srcs: [
|
||||||
|
"src/**/*.java",
|
||||||
|
"src/**/*.kt",
|
||||||
|
],
|
||||||
|
|
||||||
libs: [
|
libs: [
|
||||||
"android.test.runner",
|
"android.test.runner",
|
||||||
@@ -34,6 +37,7 @@ android_test {
|
|||||||
],
|
],
|
||||||
|
|
||||||
static_libs: [
|
static_libs: [
|
||||||
|
"androidx.test.ext.junit",
|
||||||
"androidx.test.rules",
|
"androidx.test.rules",
|
||||||
"androidx.test.uiautomator_uiautomator",
|
"androidx.test.uiautomator_uiautomator",
|
||||||
"app-helpers-core",
|
"app-helpers-core",
|
||||||
|
@@ -1,622 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 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.biometrics2.ui.view;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.junit.Assume.assumeFalse;
|
|
||||||
import static org.junit.Assume.assumeTrue;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
|
||||||
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
|
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.support.test.uiautomator.By;
|
|
||||||
import android.support.test.uiautomator.UiDevice;
|
|
||||||
import android.support.test.uiautomator.UiObject2;
|
|
||||||
import android.support.test.uiautomator.Until;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternChecker;
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
|
||||||
import com.android.internal.widget.LockscreenCredential;
|
|
||||||
import com.android.settings.biometrics2.utils.LockScreenUtil;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class FingerprintEnrollmentActivityTest {
|
|
||||||
|
|
||||||
private static final String TAG = "FingerprintEnrollmentActivityTest";
|
|
||||||
|
|
||||||
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
|
|
||||||
private static final String ACTIVITY_CLASS_NAME =
|
|
||||||
"com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity";
|
|
||||||
private static final String SUW_ACTIVITY_CLASS_NAME = ACTIVITY_CLASS_NAME + "$SetupActivity";
|
|
||||||
private static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
|
|
||||||
private static final String EXTRA_SKIP_INTRO = "skip_intro";
|
|
||||||
private static final String EXTRA_SKIP_FIND_SENSOR = "skip_find_sensor";
|
|
||||||
private static final String EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type";
|
|
||||||
private static final String EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle";
|
|
||||||
private static final String TEST_PIN = "1234";
|
|
||||||
|
|
||||||
private static final String DO_IT_LATER = "Do it later";
|
|
||||||
|
|
||||||
private static final String UDFPS_ENROLLING_TITLE = "Touch & hold the fingerprint sensor";
|
|
||||||
private static final String SFPS_ENROLLING_TITLE =
|
|
||||||
"Lift, then touch. Move your finger slightly each time.";
|
|
||||||
private static final String RFPS_ENROLLING_TITLE = "Lift, then touch again";
|
|
||||||
|
|
||||||
private UiDevice mDevice;
|
|
||||||
private byte[] mToken = new byte[]{};
|
|
||||||
private Context mContext;
|
|
||||||
private boolean mFingerprintPropCallbackLaunched;
|
|
||||||
private boolean mCanAssumeUdfps;
|
|
||||||
private boolean mCanAssumeSfps;
|
|
||||||
private String mEnrollingTitle;
|
|
||||||
|
|
||||||
private static final int IDLE_TIMEOUT = 10000;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws InterruptedException {
|
|
||||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
|
||||||
mContext = InstrumentationRegistry.getContext();
|
|
||||||
|
|
||||||
// Stop every test if it is not a fingerprint device
|
|
||||||
assumeTrue(mContext.getPackageManager().hasSystemFeature(
|
|
||||||
PackageManager.FEATURE_FINGERPRINT));
|
|
||||||
|
|
||||||
final FingerprintManager fingerprintManager = mContext.getSystemService(
|
|
||||||
FingerprintManager.class);
|
|
||||||
mFingerprintPropCallbackLaunched = false;
|
|
||||||
fingerprintManager.addAuthenticatorsRegisteredCallback(
|
|
||||||
new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
|
|
||||||
@Override
|
|
||||||
public void onAllAuthenticatorsRegistered(
|
|
||||||
List<FingerprintSensorPropertiesInternal> list) {
|
|
||||||
mFingerprintPropCallbackLaunched = true;
|
|
||||||
|
|
||||||
assertThat(list).isNotNull();
|
|
||||||
assertThat(list).isNotEmpty();
|
|
||||||
final FingerprintSensorPropertiesInternal prop = list.get(0);
|
|
||||||
mCanAssumeUdfps = prop.isAnyUdfpsType();
|
|
||||||
mCanAssumeSfps = prop.isAnySidefpsType();
|
|
||||||
if (mCanAssumeUdfps) {
|
|
||||||
mEnrollingTitle = UDFPS_ENROLLING_TITLE;
|
|
||||||
} else if (mCanAssumeSfps) {
|
|
||||||
mEnrollingTitle = SFPS_ENROLLING_TITLE;
|
|
||||||
} else {
|
|
||||||
mEnrollingTitle = RFPS_ENROLLING_TITLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (long i = 0; i < IDLE_TIMEOUT && !mFingerprintPropCallbackLaunched; i += 100L) {
|
|
||||||
Thread.sleep(100L);
|
|
||||||
}
|
|
||||||
assertThat(mFingerprintPropCallbackLaunched).isTrue();
|
|
||||||
|
|
||||||
mDevice.pressHome();
|
|
||||||
|
|
||||||
// Stop settings before performing test
|
|
||||||
try {
|
|
||||||
mDevice.executeShellCommand("am force-stop " + SETTINGS_PACKAGE_NAME);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Fail to stop settings app", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception {
|
|
||||||
LockScreenUtil.resetLockscreen(TEST_PIN);
|
|
||||||
mDevice.pressHome();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroChooseLock() {
|
|
||||||
final Intent intent = newActivityIntent(false);
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Choose your backup screen lock method")),
|
|
||||||
IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyIntroPage() {
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
for (long i = 0; i < IDLE_TIMEOUT; i += 100L) {
|
|
||||||
if (mDevice.wait(Until.hasObject(By.text("More")), 50L)) {
|
|
||||||
break;
|
|
||||||
} else if (mDevice.wait(Until.hasObject(By.text("I agree")), 50L)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Click more btn at most twice and the introduction should stay in the last page
|
|
||||||
UiObject2 moreBtn;
|
|
||||||
for (int i = 0; i < 2 && (moreBtn = mDevice.findObject(By.text("More"))) != null; ++i) {
|
|
||||||
moreBtn.click();
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
mDevice.wait(Until.hasObject(By.text("More")), IDLE_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("No thanks")), IDLE_TIMEOUT)).isTrue();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("I agree")), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_withUdfps_clickStart() {
|
|
||||||
assumeTrue(mCanAssumeUdfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindUdfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
assertThat(lottie.isClickable()).isTrue();
|
|
||||||
final UiObject2 startBtn = mDevice.findObject(By.text("Start"));
|
|
||||||
assertThat(startBtn.isClickable()).isTrue();
|
|
||||||
startBtn.click();
|
|
||||||
|
|
||||||
// Enrolling page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_withUdfps_clickLottie() {
|
|
||||||
assumeTrue(mCanAssumeUdfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindUdfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
assertThat(lottie.isClickable()).isTrue();
|
|
||||||
final UiObject2 startBtn = mDevice.findObject(By.text("Start"));
|
|
||||||
assertThat(startBtn.isClickable()).isTrue();
|
|
||||||
lottie.click();
|
|
||||||
|
|
||||||
// Enrolling page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_withSfps() {
|
|
||||||
assumeTrue(mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindSfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
|
|
||||||
// We don't have view which can be clicked to run to next page, stop at here.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_withRfps() {
|
|
||||||
assumeFalse(mCanAssumeUdfps || mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindRfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
if (lottie == null) {
|
|
||||||
// FindSfps page shall have an animation view if no lottie view
|
|
||||||
assertThat(mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"fingerprint_sensor_location_animation"))).isNotNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_clickNoThanksInIntroPage() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 noThanksBtn = mDevice.findObject(By.text("No thanks"));
|
|
||||||
assertThat(noThanksBtn).isNotNull();
|
|
||||||
noThanksBtn.click();
|
|
||||||
|
|
||||||
// Back to home
|
|
||||||
mDevice.waitForWindowUpdate("com.android.settings", IDLE_TIMEOUT);
|
|
||||||
assertThat(mDevice.findObject(By.text("No thanks"))).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_clickSkipInFindSensor() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(false);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindSensor page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 doItLaterBtn = mDevice.findObject(By.text(DO_IT_LATER));
|
|
||||||
assertThat(doItLaterBtn).isNotNull();
|
|
||||||
assertThat(doItLaterBtn.isClickable()).isTrue();
|
|
||||||
doItLaterBtn.click();
|
|
||||||
|
|
||||||
// Back to home
|
|
||||||
mDevice.waitForWindowUpdate("com.android.settings", IDLE_TIMEOUT);
|
|
||||||
assertThat(mDevice.findObject(By.text(DO_IT_LATER))).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(true);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindSensor page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 doItLaterBtn = mDevice.findObject(By.text(DO_IT_LATER));
|
|
||||||
assertThat(doItLaterBtn).isNotNull();
|
|
||||||
assertThat(doItLaterBtn.isClickable()).isTrue();
|
|
||||||
doItLaterBtn.click();
|
|
||||||
|
|
||||||
// SkipSetupFindFpsDialog
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Skip fingerprint?")),
|
|
||||||
IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 skipAnywayBtn = mDevice.findObject(By.text("Skip anyway"));
|
|
||||||
assertThat(skipAnywayBtn).isNotNull();
|
|
||||||
assertThat(skipAnywayBtn.isClickable()).isTrue();
|
|
||||||
skipAnywayBtn.click();
|
|
||||||
|
|
||||||
// Back to home
|
|
||||||
mDevice.waitForWindowUpdate("com.android.settings", IDLE_TIMEOUT);
|
|
||||||
assertThat(mDevice.findObject(By.text("Skip anyway"))).isNull();
|
|
||||||
assertThat(mDevice.findObject(By.text(DO_IT_LATER))).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchIntroWithGkPwHandle(true);
|
|
||||||
|
|
||||||
// Intro page
|
|
||||||
verifyIntroPage();
|
|
||||||
final UiObject2 agreeBtn = mDevice.findObject(By.text("I agree"));
|
|
||||||
assertThat(agreeBtn).isNotNull();
|
|
||||||
agreeBtn.click();
|
|
||||||
|
|
||||||
// FindSensor page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 doItLaterBtn = mDevice.findObject(By.text(DO_IT_LATER));
|
|
||||||
assertThat(doItLaterBtn).isNotNull();
|
|
||||||
assertThat(doItLaterBtn.isClickable()).isTrue();
|
|
||||||
doItLaterBtn.click();
|
|
||||||
|
|
||||||
// SkipSetupFindFpsDialog
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Skip fingerprint?")), IDLE_TIMEOUT))
|
|
||||||
.isTrue();
|
|
||||||
final UiObject2 goBackBtn = mDevice.findObject(By.text("Go back"));
|
|
||||||
assertThat(goBackBtn).isNotNull();
|
|
||||||
assertThat(goBackBtn.isClickable()).isTrue();
|
|
||||||
goBackBtn.click();
|
|
||||||
|
|
||||||
// FindSensor page again
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIntroCheckPin() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
final Intent intent = newActivityIntent(false);
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Enter your device PIN to continue")),
|
|
||||||
IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnrollingWithGkPwHandle() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchEnrollingWithGkPwHandle();
|
|
||||||
|
|
||||||
// Enrolling screen
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnrollingIconTouchDialog_withSfps() {
|
|
||||||
assumeTrue(mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchEnrollingWithGkPwHandle();
|
|
||||||
|
|
||||||
// Enrolling screen
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
|
|
||||||
lottie.click();
|
|
||||||
lottie.click();
|
|
||||||
lottie.click();
|
|
||||||
|
|
||||||
// IconTouchDialog
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Touch the sensor instead")), IDLE_TIMEOUT))
|
|
||||||
.isTrue();
|
|
||||||
final UiObject2 okButton = mDevice.findObject(By.text("OK"));
|
|
||||||
assertThat(okButton).isNotNull();
|
|
||||||
|
|
||||||
okButton.click();
|
|
||||||
|
|
||||||
// Enrolling screen again
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnrollingIconTouchDialog_withRfps() {
|
|
||||||
assumeFalse(mCanAssumeUdfps || mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchEnrollingWithGkPwHandle();
|
|
||||||
|
|
||||||
// Enrolling screen
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"fingerprint_progress_bar"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
|
|
||||||
lottie.click();
|
|
||||||
lottie.click();
|
|
||||||
lottie.click();
|
|
||||||
|
|
||||||
// IconTouchDialog
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text("Whoops, that\u2019s not the sensor")),
|
|
||||||
IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 okButton = mDevice.findObject(By.text("OK"));
|
|
||||||
assertThat(okButton).isNotNull();
|
|
||||||
|
|
||||||
okButton.click();
|
|
||||||
|
|
||||||
// Enrolling screen again
|
|
||||||
mDevice.waitForIdle();
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindUdfpsWithGkPwHandle_clickStart() {
|
|
||||||
assumeTrue(mCanAssumeUdfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchFindSensorWithGkPwHandle();
|
|
||||||
|
|
||||||
// FindUdfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
assertThat(lottie.isClickable()).isTrue();
|
|
||||||
final UiObject2 startBtn = mDevice.findObject(By.text("Start"));
|
|
||||||
assertThat(startBtn.isClickable()).isTrue();
|
|
||||||
startBtn.click();
|
|
||||||
|
|
||||||
// Enrolling page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindUdfpsWithGkPwHandle_clickLottie() {
|
|
||||||
assumeTrue(mCanAssumeUdfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchFindSensorWithGkPwHandle();
|
|
||||||
|
|
||||||
// FindUdfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
assertThat(lottie.isClickable()).isTrue();
|
|
||||||
final UiObject2 startBtn = mDevice.findObject(By.text("Start"));
|
|
||||||
assertThat(startBtn.isClickable()).isTrue();
|
|
||||||
lottie.click();
|
|
||||||
|
|
||||||
// Enrolling page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(mEnrollingTitle)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindSfpsWithGkPwHandle() {
|
|
||||||
assumeTrue(mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchFindSensorWithGkPwHandle();
|
|
||||||
|
|
||||||
// FindSfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
assertThat(lottie).isNotNull();
|
|
||||||
|
|
||||||
// We don't have view which can be clicked to run to next page, stop at here.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindRfpsWithGkPwHandle() {
|
|
||||||
assumeFalse(mCanAssumeUdfps || mCanAssumeSfps);
|
|
||||||
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchFindSensorWithGkPwHandle();
|
|
||||||
|
|
||||||
// FindRfps page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 lottie = mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"illustration_lottie"));
|
|
||||||
if (lottie == null) {
|
|
||||||
// FindSfps page shall have an animation view if no lottie view
|
|
||||||
assertThat(mDevice.findObject(By.res(SETTINGS_PACKAGE_NAME,
|
|
||||||
"fingerprint_sensor_location_animation"))).isNotNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindSensorWithGkPwHandle_clickSkipInFindSensor() {
|
|
||||||
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true);
|
|
||||||
|
|
||||||
launchFindSensorWithGkPwHandle();
|
|
||||||
|
|
||||||
// FindSensor page
|
|
||||||
assertThat(mDevice.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
final UiObject2 doItLaterBtn = mDevice.findObject(By.text(DO_IT_LATER));
|
|
||||||
assertThat(doItLaterBtn).isNotNull();
|
|
||||||
assertThat(doItLaterBtn.isClickable()).isTrue();
|
|
||||||
doItLaterBtn.click();
|
|
||||||
|
|
||||||
// Back to home
|
|
||||||
mDevice.waitForWindowUpdate("com.android.settings", IDLE_TIMEOUT);
|
|
||||||
assertThat(mDevice.wait(Until.gone(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void launchIntroWithGkPwHandle(boolean isSuw) {
|
|
||||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
|
|
||||||
final LockscreenCredential lockscreenCredential = LockscreenCredential.createPin(TEST_PIN);
|
|
||||||
final int userId = UserHandle.myUserId();
|
|
||||||
final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
|
|
||||||
final Intent intent = newActivityIntent(isSuw);
|
|
||||||
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.getGatekeeperPasswordHandle());
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
};
|
|
||||||
LockPatternChecker.verifyCredential(lockPatternUtils, lockscreenCredential,
|
|
||||||
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void launchFindSensorWithGkPwHandle() {
|
|
||||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
|
|
||||||
final LockscreenCredential lockscreenCredential = LockscreenCredential.createPin(TEST_PIN);
|
|
||||||
final int userId = UserHandle.myUserId();
|
|
||||||
final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
|
|
||||||
final Intent intent = newActivityIntent(false);
|
|
||||||
intent.putExtra(EXTRA_SKIP_INTRO, true);
|
|
||||||
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.getGatekeeperPasswordHandle());
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
};
|
|
||||||
LockPatternChecker.verifyCredential(lockPatternUtils, lockscreenCredential,
|
|
||||||
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void launchEnrollingWithGkPwHandle() {
|
|
||||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
|
|
||||||
final LockscreenCredential lockscreenCredential = LockscreenCredential.createPin(TEST_PIN);
|
|
||||||
final int userId = UserHandle.myUserId();
|
|
||||||
final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
|
|
||||||
final Intent intent = newActivityIntent(false);
|
|
||||||
intent.putExtra(EXTRA_SKIP_FIND_SENSOR, true);
|
|
||||||
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.getGatekeeperPasswordHandle());
|
|
||||||
mContext.startActivity(intent);
|
|
||||||
};
|
|
||||||
LockPatternChecker.verifyCredential(lockPatternUtils, lockscreenCredential,
|
|
||||||
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Intent newActivityIntent(boolean isSuw) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setClassName(SETTINGS_PACKAGE_NAME,
|
|
||||||
isSuw ? SUW_ACTIVITY_CLASS_NAME : ACTIVITY_CLASS_NAME);
|
|
||||||
if (isSuw) {
|
|
||||||
intent.putExtra(EXTRA_IS_SETUP_FLOW, true);
|
|
||||||
}
|
|
||||||
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, 1);
|
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, mContext.getUserId());
|
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
return intent;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,632 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.biometrics2.ui.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager.FEATURE_FINGERPRINT
|
||||||
|
import android.hardware.fingerprint.FingerprintManager
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
|
||||||
|
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.support.test.uiautomator.By
|
||||||
|
import android.support.test.uiautomator.UiDevice
|
||||||
|
import android.support.test.uiautomator.UiObject2
|
||||||
|
import android.support.test.uiautomator.Until
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.android.internal.widget.LockPatternChecker
|
||||||
|
import com.android.internal.widget.LockPatternUtils
|
||||||
|
import com.android.internal.widget.LockscreenCredential
|
||||||
|
import com.android.internal.widget.VerifyCredentialResponse
|
||||||
|
import com.android.settings.biometrics2.utils.LockScreenUtil
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assume
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class FingerprintEnrollmentActivityTest {
|
||||||
|
|
||||||
|
private val context: Context by lazy {
|
||||||
|
InstrumentationRegistry.getInstrumentation().context
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fingerprintManager: FingerprintManager by lazy {
|
||||||
|
context.getSystemService(FingerprintManager::class.java)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private var fingerprintPropCallbackLaunched = false
|
||||||
|
private var canAssumeUdfps = false
|
||||||
|
private var canAssumeSfps = false
|
||||||
|
private var enrollingPageTitle: String = ""
|
||||||
|
|
||||||
|
private val device: UiDevice by lazy {
|
||||||
|
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
fun setUp() {
|
||||||
|
// Stop every test if it is not a fingerprint device
|
||||||
|
Assume.assumeTrue(context.packageManager.hasSystemFeature(FEATURE_FINGERPRINT))
|
||||||
|
|
||||||
|
fingerprintPropCallbackLaunched = false
|
||||||
|
fingerprintManager.addAuthenticatorsRegisteredCallback(
|
||||||
|
object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
|
||||||
|
override fun onAllAuthenticatorsRegistered(
|
||||||
|
list: List<FingerprintSensorPropertiesInternal>
|
||||||
|
) {
|
||||||
|
fingerprintPropCallbackLaunched = true
|
||||||
|
assertThat(list).isNotNull()
|
||||||
|
assertThat(list).isNotEmpty()
|
||||||
|
val prop = list[0]
|
||||||
|
canAssumeUdfps = prop.isAnyUdfpsType
|
||||||
|
canAssumeSfps = prop.isAnySidefpsType
|
||||||
|
enrollingPageTitle = if (canAssumeUdfps) {
|
||||||
|
UDFPS_ENROLLING_TITLE
|
||||||
|
} else if (canAssumeSfps) {
|
||||||
|
SFPS_ENROLLING_TITLE
|
||||||
|
} else {
|
||||||
|
RFPS_ENROLLING_TITLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
var i: Long = 0
|
||||||
|
while (i < IDLE_TIMEOUT && !fingerprintPropCallbackLaunched) {
|
||||||
|
Thread.sleep(100L)
|
||||||
|
i += 100L
|
||||||
|
}
|
||||||
|
assertThat(fingerprintPropCallbackLaunched).isTrue()
|
||||||
|
device.pressHome()
|
||||||
|
|
||||||
|
// Stop settings before performing test
|
||||||
|
try {
|
||||||
|
device.executeShellCommand("am force-stop $SETTINGS_PACKAGE_NAME")
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "Fail to stop settings app", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun tearDown() {
|
||||||
|
LockScreenUtil.resetLockscreen(TEST_PIN)
|
||||||
|
device.pressHome()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroChooseLock() {
|
||||||
|
val intent = newActivityIntent(false)
|
||||||
|
context.startActivity(intent)
|
||||||
|
assertThat(
|
||||||
|
device.wait(
|
||||||
|
Until.hasObject(By.text("Choose your backup screen lock method")),
|
||||||
|
IDLE_TIMEOUT
|
||||||
|
)
|
||||||
|
).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyIntroPage() {
|
||||||
|
device.waitForIdle()
|
||||||
|
run {
|
||||||
|
var i: Long = 0
|
||||||
|
while (i < IDLE_TIMEOUT) {
|
||||||
|
if (device.wait(Until.hasObject(By.text("More")), 50L)) {
|
||||||
|
break
|
||||||
|
} else if (device.wait(Until.hasObject(By.text("I agree")), 50L)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i += 100L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click more btn at most twice and the introduction should stay in the last page
|
||||||
|
var moreBtn: UiObject2? = null
|
||||||
|
var i = 0
|
||||||
|
while (i < 2 && device.findObject(By.text("More")).also { moreBtn = it } != null) {
|
||||||
|
moreBtn!!.click()
|
||||||
|
device.waitForIdle()
|
||||||
|
device.wait(Until.hasObject(By.text("More")), IDLE_TIMEOUT)
|
||||||
|
++i
|
||||||
|
}
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text("No thanks")), IDLE_TIMEOUT)).isTrue()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text("I agree")), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_withUdfps_clickStart() {
|
||||||
|
Assume.assumeTrue(canAssumeUdfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindUdfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
assertThat(lottie.isClickable).isTrue()
|
||||||
|
val startBtn = device.findObject(By.text("Start"))
|
||||||
|
assertThat(startBtn.isClickable).isTrue()
|
||||||
|
startBtn.click()
|
||||||
|
|
||||||
|
// Enrolling page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_withUdfps_clickLottie() {
|
||||||
|
Assume.assumeTrue(canAssumeUdfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindUdfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie"))
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
assertThat(lottie.isClickable).isTrue()
|
||||||
|
val startBtn = device.findObject(By.text("Start"))
|
||||||
|
assertThat(startBtn.isClickable).isTrue()
|
||||||
|
lottie.click()
|
||||||
|
|
||||||
|
// Enrolling page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_withSfps() {
|
||||||
|
Assume.assumeTrue(canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindSfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME,"illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
|
||||||
|
// We don't have view which can be clicked to run to next page, stop at here.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_withRfps() {
|
||||||
|
Assume.assumeFalse(canAssumeUdfps || canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindRfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
if (lottie == null) {
|
||||||
|
// FindSfps page shall have an animation view if no lottie view
|
||||||
|
assertThat(
|
||||||
|
device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "fingerprint_sensor_location_animation")
|
||||||
|
)
|
||||||
|
).isNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_clickNoThanksInIntroPage() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val noThanksBtn = device.findObject(By.text("No thanks"))
|
||||||
|
assertThat(noThanksBtn).isNotNull()
|
||||||
|
noThanksBtn.click()
|
||||||
|
|
||||||
|
// Back to home
|
||||||
|
device.waitForWindowUpdate(SETTINGS_PACKAGE_NAME, IDLE_TIMEOUT)
|
||||||
|
assertThat(device.findObject(By.text("No thanks"))).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_clickSkipInFindSensor() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(false)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindSensor page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val doItLaterBtn = device.findObject(By.text(DO_IT_LATER))
|
||||||
|
assertThat(doItLaterBtn).isNotNull()
|
||||||
|
assertThat(doItLaterBtn.isClickable).isTrue()
|
||||||
|
doItLaterBtn.click()
|
||||||
|
|
||||||
|
// Back to home
|
||||||
|
device.waitForWindowUpdate(SETTINGS_PACKAGE_NAME, IDLE_TIMEOUT)
|
||||||
|
assertThat(device.findObject(By.text(DO_IT_LATER))).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_clickSkipAnywayInFindFpsDialog_whenIsSuw() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(true)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindSensor page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val doItLaterBtn = device.findObject(By.text(DO_IT_LATER))
|
||||||
|
assertThat(doItLaterBtn).isNotNull()
|
||||||
|
assertThat(doItLaterBtn.isClickable).isTrue()
|
||||||
|
doItLaterBtn.click()
|
||||||
|
|
||||||
|
// SkipSetupFindFpsDialog
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text("Skip fingerprint?")), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val skipAnywayBtn = device.findObject(By.text("Skip anyway"))
|
||||||
|
assertThat(skipAnywayBtn).isNotNull()
|
||||||
|
assertThat(skipAnywayBtn.isClickable).isTrue()
|
||||||
|
skipAnywayBtn.click()
|
||||||
|
|
||||||
|
// Back to home
|
||||||
|
device.waitForWindowUpdate(SETTINGS_PACKAGE_NAME, IDLE_TIMEOUT)
|
||||||
|
assertThat(device.findObject(By.text("Skip anyway"))).isNull()
|
||||||
|
assertThat(device.findObject(By.text(DO_IT_LATER))).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroWithGkPwHandle_clickGoBackInFindFpsDialog_whenIsSuw() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchIntroWithGkPwHandle(true)
|
||||||
|
|
||||||
|
// Intro page
|
||||||
|
verifyIntroPage()
|
||||||
|
val agreeBtn = device.findObject(By.text("I agree"))
|
||||||
|
assertThat(agreeBtn).isNotNull()
|
||||||
|
agreeBtn.click()
|
||||||
|
|
||||||
|
// FindSensor page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val doItLaterBtn = device.findObject(By.text(DO_IT_LATER))
|
||||||
|
assertThat(doItLaterBtn).isNotNull()
|
||||||
|
assertThat(doItLaterBtn.isClickable).isTrue()
|
||||||
|
doItLaterBtn.click()
|
||||||
|
|
||||||
|
// SkipSetupFindFpsDialog
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text("Skip fingerprint?")), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val goBackBtn = device.findObject(By.text("Go back"))
|
||||||
|
assertThat(goBackBtn).isNotNull()
|
||||||
|
assertThat(goBackBtn.isClickable).isTrue()
|
||||||
|
goBackBtn.click()
|
||||||
|
|
||||||
|
// FindSensor page again
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIntroCheckPin() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
val intent = newActivityIntent(false)
|
||||||
|
context.startActivity(intent)
|
||||||
|
assertThat(
|
||||||
|
device.wait(
|
||||||
|
Until.hasObject(By.text("Enter your device PIN to continue")),
|
||||||
|
IDLE_TIMEOUT
|
||||||
|
)
|
||||||
|
).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEnrollingWithGkPwHandle() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchEnrollingWithGkPwHandle()
|
||||||
|
|
||||||
|
// Enrolling screen
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEnrollingIconTouchDialog_withSfps() {
|
||||||
|
Assume.assumeTrue(canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchEnrollingWithGkPwHandle()
|
||||||
|
|
||||||
|
// Enrolling screen
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
lottie.click()
|
||||||
|
lottie.click()
|
||||||
|
lottie.click()
|
||||||
|
|
||||||
|
// IconTouchDialog
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(
|
||||||
|
device.wait(
|
||||||
|
Until.hasObject(By.text("Touch the sensor instead")),
|
||||||
|
IDLE_TIMEOUT
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.isTrue()
|
||||||
|
val okButton = device.findObject(By.text("OK"))
|
||||||
|
assertThat(okButton).isNotNull()
|
||||||
|
okButton.click()
|
||||||
|
|
||||||
|
// Enrolling screen again
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEnrollingIconTouchDialog_withRfps() {
|
||||||
|
Assume.assumeFalse(canAssumeUdfps || canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchEnrollingWithGkPwHandle()
|
||||||
|
|
||||||
|
// Enrolling screen
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "fingerprint_progress_bar")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
lottie.click()
|
||||||
|
lottie.click()
|
||||||
|
lottie.click()
|
||||||
|
|
||||||
|
// IconTouchDialog
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(
|
||||||
|
device.wait(
|
||||||
|
Until.hasObject(By.text("Whoops, that\u2019s not the sensor")),
|
||||||
|
IDLE_TIMEOUT
|
||||||
|
)
|
||||||
|
).isTrue()
|
||||||
|
val okButton = device.findObject(By.text("OK"))
|
||||||
|
assertThat(okButton).isNotNull()
|
||||||
|
okButton.click()
|
||||||
|
|
||||||
|
// Enrolling screen again
|
||||||
|
device.waitForIdle()
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindUdfpsWithGkPwHandle_clickStart() {
|
||||||
|
Assume.assumeTrue(canAssumeUdfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchFindSensorWithGkPwHandle()
|
||||||
|
|
||||||
|
// FindUdfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
assertThat(lottie.isClickable).isTrue()
|
||||||
|
val startBtn = device.findObject(By.text("Start"))
|
||||||
|
assertThat(startBtn.isClickable).isTrue()
|
||||||
|
startBtn.click()
|
||||||
|
|
||||||
|
// Enrolling page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindUdfpsWithGkPwHandle_clickLottie() {
|
||||||
|
Assume.assumeTrue(canAssumeUdfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchFindSensorWithGkPwHandle()
|
||||||
|
|
||||||
|
// FindUdfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
assertThat(lottie.isClickable).isTrue()
|
||||||
|
val startBtn = device.findObject(By.text("Start"))
|
||||||
|
assertThat(startBtn.isClickable).isTrue()
|
||||||
|
lottie.click()
|
||||||
|
|
||||||
|
// Enrolling page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(enrollingPageTitle)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindSfpsWithGkPwHandle() {
|
||||||
|
Assume.assumeTrue(canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchFindSensorWithGkPwHandle()
|
||||||
|
|
||||||
|
// FindSfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(SETTINGS_PACKAGE_NAME, "illustration_lottie")
|
||||||
|
)
|
||||||
|
assertThat(lottie).isNotNull()
|
||||||
|
|
||||||
|
// We don't have view which can be clicked to run to next page, stop at here.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindRfpsWithGkPwHandle() {
|
||||||
|
Assume.assumeFalse(canAssumeUdfps || canAssumeSfps)
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchFindSensorWithGkPwHandle()
|
||||||
|
|
||||||
|
// FindRfps page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val lottie = device.findObject(
|
||||||
|
By.res(
|
||||||
|
SETTINGS_PACKAGE_NAME,
|
||||||
|
"illustration_lottie"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (lottie == null) {
|
||||||
|
// FindSfps page shall have an animation view if no lottie view
|
||||||
|
assertThat(
|
||||||
|
device.findObject(
|
||||||
|
By.res(
|
||||||
|
SETTINGS_PACKAGE_NAME,
|
||||||
|
"fingerprint_sensor_location_animation"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).isNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFindSensorWithGkPwHandle_clickSkipInFindSensor() {
|
||||||
|
LockScreenUtil.setLockscreen(LockScreenUtil.LockscreenType.PIN, TEST_PIN, true)
|
||||||
|
launchFindSensorWithGkPwHandle()
|
||||||
|
|
||||||
|
// FindSensor page
|
||||||
|
assertThat(device.wait(Until.hasObject(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
val doItLaterBtn = device.findObject(By.text(DO_IT_LATER))
|
||||||
|
assertThat(doItLaterBtn).isNotNull()
|
||||||
|
assertThat(doItLaterBtn.isClickable).isTrue()
|
||||||
|
doItLaterBtn.click()
|
||||||
|
|
||||||
|
// Back to home
|
||||||
|
device.waitForWindowUpdate(SETTINGS_PACKAGE_NAME, IDLE_TIMEOUT)
|
||||||
|
assertThat(device.wait(Until.gone(By.text(DO_IT_LATER)), IDLE_TIMEOUT)).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchIntroWithGkPwHandle(isSuw: Boolean) {
|
||||||
|
val lockPatternUtils = LockPatternUtils(context)
|
||||||
|
val lockscreenCredential = LockscreenCredential.createPin(TEST_PIN)
|
||||||
|
val userId = UserHandle.myUserId()
|
||||||
|
val onVerifyCallback =
|
||||||
|
LockPatternChecker.OnVerifyCallback { response: VerifyCredentialResponse, _: Int ->
|
||||||
|
val intent = newActivityIntent(isSuw)
|
||||||
|
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.gatekeeperPasswordHandle)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
LockPatternChecker.verifyCredential(
|
||||||
|
lockPatternUtils, lockscreenCredential,
|
||||||
|
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchFindSensorWithGkPwHandle() {
|
||||||
|
val lockPatternUtils = LockPatternUtils(context)
|
||||||
|
val lockscreenCredential = LockscreenCredential.createPin(TEST_PIN)
|
||||||
|
val userId = UserHandle.myUserId()
|
||||||
|
val onVerifyCallback =
|
||||||
|
LockPatternChecker.OnVerifyCallback { response: VerifyCredentialResponse, _: Int ->
|
||||||
|
val intent = newActivityIntent(false)
|
||||||
|
intent.putExtra(EXTRA_SKIP_INTRO, true)
|
||||||
|
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.gatekeeperPasswordHandle)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
LockPatternChecker.verifyCredential(
|
||||||
|
lockPatternUtils, lockscreenCredential,
|
||||||
|
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchEnrollingWithGkPwHandle() {
|
||||||
|
val lockPatternUtils = LockPatternUtils(context)
|
||||||
|
val lockscreenCredential = LockscreenCredential.createPin(TEST_PIN)
|
||||||
|
val userId = UserHandle.myUserId()
|
||||||
|
val onVerifyCallback =
|
||||||
|
LockPatternChecker.OnVerifyCallback { response: VerifyCredentialResponse, _: Int ->
|
||||||
|
val intent = newActivityIntent(false)
|
||||||
|
intent.putExtra(EXTRA_SKIP_FIND_SENSOR, true)
|
||||||
|
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, response.gatekeeperPasswordHandle)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
LockPatternChecker.verifyCredential(
|
||||||
|
lockPatternUtils, lockscreenCredential,
|
||||||
|
userId, LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, onVerifyCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newActivityIntent(isSuw: Boolean): Intent {
|
||||||
|
val intent = Intent()
|
||||||
|
intent.setClassName(
|
||||||
|
SETTINGS_PACKAGE_NAME,
|
||||||
|
if (isSuw) SUW_ACTIVITY_CLASS_NAME else ACTIVITY_CLASS_NAME
|
||||||
|
)
|
||||||
|
if (isSuw) {
|
||||||
|
intent.putExtra(EXTRA_IS_SETUP_FLOW, true)
|
||||||
|
}
|
||||||
|
intent.putExtra(EXTRA_PAGE_TRANSITION_TYPE, 1)
|
||||||
|
intent.putExtra(Intent.EXTRA_USER_ID, context.userId)
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "FingerprintEnrollmentActivityTest"
|
||||||
|
const val SETTINGS_PACKAGE_NAME = "com.android.settings"
|
||||||
|
private const val ACTIVITY_CLASS_NAME =
|
||||||
|
"com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity"
|
||||||
|
private const val SUW_ACTIVITY_CLASS_NAME = "$ACTIVITY_CLASS_NAME\$SetupActivity"
|
||||||
|
private const val EXTRA_IS_SETUP_FLOW = "isSetupFlow"
|
||||||
|
private const val EXTRA_SKIP_INTRO = "skip_intro"
|
||||||
|
private const val EXTRA_SKIP_FIND_SENSOR = "skip_find_sensor"
|
||||||
|
private const val EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type"
|
||||||
|
private const val EXTRA_KEY_GK_PW_HANDLE = "gk_pw_handle"
|
||||||
|
private const val TEST_PIN = "1234"
|
||||||
|
private const val DO_IT_LATER = "Do it later"
|
||||||
|
private const val UDFPS_ENROLLING_TITLE = "Touch & hold the fingerprint sensor"
|
||||||
|
private const val SFPS_ENROLLING_TITLE =
|
||||||
|
"Lift, then touch. Move your finger slightly each time."
|
||||||
|
private const val RFPS_ENROLLING_TITLE = "Lift, then touch again"
|
||||||
|
private const val IDLE_TIMEOUT = 10000L
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user