Merge "Fix FingerprintEnrollmentActivity rotaiton crash"
This commit is contained in:
@@ -1,57 +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.factory;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentFactory;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
|
|
||||||
import com.android.settings.biometrics2.ui.view.FingerprintEnrollIntroFragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fragment factory for biometrics
|
|
||||||
*/
|
|
||||||
public class BiometricsFragmentFactory extends FragmentFactory {
|
|
||||||
|
|
||||||
private final Application mApplication;
|
|
||||||
private final ViewModelProvider mViewModelProvider;
|
|
||||||
|
|
||||||
public BiometricsFragmentFactory(Application application,
|
|
||||||
ViewModelProvider viewModelProvider) {
|
|
||||||
mApplication = application;
|
|
||||||
mViewModelProvider = viewModelProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
|
|
||||||
final Class<? extends Fragment> clazz = loadFragmentClass(classLoader, className);
|
|
||||||
if (FingerprintEnrollIntroFragment.class.equals(clazz)) {
|
|
||||||
final DevicePolicyManager devicePolicyManager =
|
|
||||||
mApplication.getSystemService(DevicePolicyManager.class);
|
|
||||||
if (devicePolicyManager != null) {
|
|
||||||
return new FingerprintEnrollIntroFragment(mViewModelProvider,
|
|
||||||
devicePolicyManager.getResources());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.instantiate(classLoader, className);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,6 +22,7 @@ import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_C
|
|||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -80,17 +81,30 @@ public final class CredentialModel {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Long mClearGkPwHandleMillis = null;
|
private Long mClearGkPwHandleMillis = null;
|
||||||
|
|
||||||
public CredentialModel(@NonNull Intent intent, @NonNull Clock clock) {
|
public CredentialModel(@NonNull Bundle bundle, @NonNull Clock clock) {
|
||||||
mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
mUserId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||||
mSensorId = intent.getIntExtra(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
|
mSensorId = bundle.getInt(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
|
||||||
mChallenge = intent.getLongExtra(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
|
mChallenge = bundle.getLong(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
|
||||||
mToken = intent.getByteArrayExtra(EXTRA_KEY_CHALLENGE_TOKEN);
|
mToken = bundle.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||||
mGkPwHandle = intent.getLongExtra(EXTRA_KEY_GK_PW_HANDLE,
|
mGkPwHandle = bundle.getLong(EXTRA_KEY_GK_PW_HANDLE, INVALID_GK_PW_HANDLE);
|
||||||
INVALID_GK_PW_HANDLE);
|
|
||||||
mClock = clock;
|
mClock = clock;
|
||||||
mInitMillis = mClock.millis();
|
mInitMillis = mClock.millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a bundle which can be used to recreate CredentialModel
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Bundle getBundle() {
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(Intent.EXTRA_USER_ID, mUserId);
|
||||||
|
bundle.putInt(EXTRA_KEY_SENSOR_ID, mSensorId);
|
||||||
|
bundle.putLong(EXTRA_KEY_CHALLENGE, mChallenge);
|
||||||
|
bundle.putByteArray(EXTRA_KEY_CHALLENGE_TOKEN, mToken);
|
||||||
|
bundle.putLong(EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get userId for this credential
|
* Get userId for this credential
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroSt
|
|||||||
import static com.google.android.setupdesign.util.DynamicColorPalette.ColorType.ACCENT;
|
import static com.google.android.setupdesign.util.DynamicColorPalette.ColorType.ACCENT;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.admin.DevicePolicyResourcesManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
import android.graphics.PorterDuffColorFilter;
|
||||||
@@ -63,9 +63,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
|||||||
|
|
||||||
private static final String TAG = "FingerprintEnrollIntroFragment";
|
private static final String TAG = "FingerprintEnrollIntroFragment";
|
||||||
|
|
||||||
@NonNull private final ViewModelProvider mViewModelProvider;
|
|
||||||
@Nullable private final DevicePolicyResourcesManager mDevicePolicyMgrRes;
|
|
||||||
|
|
||||||
private FingerprintEnrollIntroViewModel mViewModel = null;
|
private FingerprintEnrollIntroViewModel mViewModel = null;
|
||||||
|
|
||||||
private View mView = null;
|
private View mView = null;
|
||||||
@@ -75,12 +72,8 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
|||||||
private TextView mFooterMessage6 = null;
|
private TextView mFooterMessage6 = null;
|
||||||
@Nullable private PorterDuffColorFilter mIconColorFilter;
|
@Nullable private PorterDuffColorFilter mIconColorFilter;
|
||||||
|
|
||||||
public FingerprintEnrollIntroFragment(
|
public FingerprintEnrollIntroFragment() {
|
||||||
@NonNull ViewModelProvider viewModelProvider,
|
|
||||||
@Nullable DevicePolicyResourcesManager devicePolicyMgrRes) {
|
|
||||||
super();
|
super();
|
||||||
mViewModelProvider = viewModelProvider;
|
|
||||||
mDevicePolicyMgrRes = devicePolicyMgrRes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -197,7 +190,8 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull Context context) {
|
public void onAttach(@NonNull Context context) {
|
||||||
mViewModel = mViewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
mViewModel = new ViewModelProvider(getActivity())
|
||||||
|
.get(FingerprintEnrollIntroViewModel.class);
|
||||||
getLifecycle().addObserver(mViewModel);
|
getLifecycle().addObserver(mViewModel);
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
}
|
}
|
||||||
@@ -232,12 +226,16 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
|||||||
private String getDescriptionDisabledByAdmin(@NonNull Context context) {
|
private String getDescriptionDisabledByAdmin(@NonNull Context context) {
|
||||||
final int defaultStrId =
|
final int defaultStrId =
|
||||||
R.string.security_settings_fingerprint_enroll_introduction_message_unlock_disabled;
|
R.string.security_settings_fingerprint_enroll_introduction_message_unlock_disabled;
|
||||||
if (mDevicePolicyMgrRes == null) {
|
|
||||||
|
final DevicePolicyManager devicePolicyManager = getActivity()
|
||||||
|
.getSystemService(DevicePolicyManager.class);
|
||||||
|
if (devicePolicyManager != null) {
|
||||||
|
return devicePolicyManager.getResources().getString(FINGERPRINT_UNLOCK_DISABLED,
|
||||||
|
() -> context.getString(defaultStrId));
|
||||||
|
} else {
|
||||||
Log.w(TAG, "getDescriptionDisabledByAdmin, null device policy manager res");
|
Log.w(TAG, "getDescriptionDisabledByAdmin, null device policy manager res");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return mDevicePolicyMgrRes.getString(FINGERPRINT_UNLOCK_DISABLED,
|
|
||||||
() -> context.getString(defaultStrId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setHeaderText(@NonNull Activity activity, int resId) {
|
private void setHeaderText(@NonNull Activity activity, int resId) {
|
||||||
|
|||||||
@@ -19,20 +19,19 @@ package com.android.settings.biometrics2.ui.view;
|
|||||||
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
|
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
|
||||||
|
|
||||||
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR;
|
import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR;
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE;
|
|
||||||
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_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_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.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
|
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_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.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
import androidx.activity.result.ActivityResult;
|
||||||
@@ -42,7 +41,6 @@ import androidx.annotation.ColorInt;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.lifecycle.viewmodel.CreationExtras;
|
import androidx.lifecycle.viewmodel.CreationExtras;
|
||||||
import androidx.lifecycle.viewmodel.MutableCreationExtras;
|
import androidx.lifecycle.viewmodel.MutableCreationExtras;
|
||||||
@@ -51,11 +49,9 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
import com.android.settings.biometrics.BiometricEnrollBase;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
||||||
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollEnrolling;
|
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
|
||||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
||||||
import com.android.settings.biometrics2.factory.BiometricsFragmentFactory;
|
|
||||||
import com.android.settings.biometrics2.factory.BiometricsViewModelFactory;
|
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.model.EnrollmentRequest;
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
|
||||||
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator;
|
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator;
|
||||||
@@ -102,12 +98,12 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
getLifecycle().addObserver(mViewModel);
|
getLifecycle().addObserver(mViewModel);
|
||||||
|
|
||||||
mAutoCredentialViewModel = viewModelProvider.get(AutoCredentialViewModel.class);
|
mAutoCredentialViewModel = viewModelProvider.get(AutoCredentialViewModel.class);
|
||||||
mAutoCredentialViewModel.setCredentialModel(new CredentialModel(getIntent(),
|
mAutoCredentialViewModel.setCredentialModel(savedInstanceState, getIntent());
|
||||||
SystemClock.elapsedRealtimeClock()));
|
mAutoCredentialViewModel.getGenerateChallengeFailLiveData().observe(this,
|
||||||
getLifecycle().addObserver(mAutoCredentialViewModel);
|
this::onGenerateChallengeFail);
|
||||||
|
|
||||||
mViewModel.getSetResultLiveData().observe(this, this::onSetActivityResult);
|
mViewModel.getSetResultLiveData().observe(this, this::onSetActivityResult);
|
||||||
mAutoCredentialViewModel.getActionLiveData().observe(this, this::onCredentialAction);
|
checkCredential();
|
||||||
|
|
||||||
// Theme
|
// Theme
|
||||||
setTheme(mViewModel.getRequest().getTheme());
|
setTheme(mViewModel.getRequest().getTheme());
|
||||||
@@ -116,21 +112,29 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
|
|
||||||
// fragment
|
// fragment
|
||||||
setContentView(R.layout.biometric_enrollment_container);
|
setContentView(R.layout.biometric_enrollment_container);
|
||||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
|
||||||
fragmentManager.setFragmentFactory(
|
|
||||||
new BiometricsFragmentFactory(getApplication(), viewModelProvider));
|
|
||||||
|
|
||||||
final FingerprintEnrollIntroViewModel fingerprintEnrollIntroViewModel =
|
final FingerprintEnrollIntroViewModel fingerprintEnrollIntroViewModel =
|
||||||
viewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
viewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
||||||
fingerprintEnrollIntroViewModel.setEnrollmentRequest(mViewModel.getRequest());
|
fingerprintEnrollIntroViewModel.setEnrollmentRequest(mViewModel.getRequest());
|
||||||
fingerprintEnrollIntroViewModel.setUserId(mAutoCredentialViewModel.getUserId());
|
fingerprintEnrollIntroViewModel.setUserId(mAutoCredentialViewModel.getUserId());
|
||||||
|
|
||||||
|
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action when
|
||||||
|
// recreate
|
||||||
|
fingerprintEnrollIntroViewModel.clearActionLiveData();
|
||||||
fingerprintEnrollIntroViewModel.getActionLiveData().observe(
|
fingerprintEnrollIntroViewModel.getActionLiveData().observe(
|
||||||
this, this::observeIntroAction);
|
this, this::observeIntroAction);
|
||||||
final String tag = "FingerprintEnrollIntroFragment";
|
if (savedInstanceState == null) {
|
||||||
fragmentManager.beginTransaction()
|
final String tag = "FingerprintEnrollIntroFragment";
|
||||||
.setReorderingAllowed(true)
|
getSupportFragmentManager().beginTransaction()
|
||||||
.add(R.id.fragment_container_view, FingerprintEnrollIntroFragment.class, null, tag)
|
.setReorderingAllowed(true)
|
||||||
.commit();
|
.add(R.id.fragment_container_view, FingerprintEnrollIntroFragment.class, null,
|
||||||
|
tag)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onGenerateChallengeFail(@NonNull Boolean isFail) {
|
||||||
|
onSetActivityResult(new ActivityResult(RESULT_CANCELED, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSetActivityResult(@NonNull ActivityResult result) {
|
private void onSetActivityResult(@NonNull ActivityResult result) {
|
||||||
@@ -141,8 +145,8 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCredentialAction(@NonNull Integer action) {
|
private void checkCredential() {
|
||||||
switch (action) {
|
switch (mAutoCredentialViewModel.checkCredential()) {
|
||||||
case CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK: {
|
case CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK: {
|
||||||
final Intent intent = mAutoCredentialViewModel.getChooseLockIntent(this,
|
final Intent intent = mAutoCredentialViewModel.getChooseLockIntent(this,
|
||||||
mViewModel.getRequest().isSuw(), mViewModel.getRequest().getSuwExtras());
|
mViewModel.getRequest().isSuw(), mViewModel.getRequest().getSuwExtras());
|
||||||
@@ -168,12 +172,9 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE: {
|
case CREDENTIAL_VALID:
|
||||||
Log.w(TAG, "observeCredentialLiveData, finish with action:" + action);
|
case CREDENTIAL_IS_GENERATING_CHALLENGE: {
|
||||||
if (mViewModel.getRequest().isAfterSuwOrSuwSuggestedAction()) {
|
// Do nothing
|
||||||
setResult(Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,10 +187,15 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
if (mAutoCredentialViewModel.checkNewCredentialFromActivityResult(
|
if (mAutoCredentialViewModel.checkNewCredentialFromActivityResult(
|
||||||
isChooseLock, activityResult)) {
|
isChooseLock, activityResult)) {
|
||||||
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
|
||||||
|
} else {
|
||||||
|
onSetActivityResult(activityResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void observeIntroAction(@NonNull Integer action) {
|
private void observeIntroAction(@Nullable Integer action) {
|
||||||
|
if (action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
|
case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
|
||||||
onSetActivityResult(
|
onSetActivityResult(
|
||||||
@@ -207,9 +213,9 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
Log.w(TAG, "startNext, isSuw:" + isSuw + ", fail to set isWaiting flag");
|
Log.w(TAG, "startNext, isSuw:" + isSuw + ", fail to set isWaiting flag");
|
||||||
}
|
}
|
||||||
final Intent intent = new Intent(this, isSuw
|
final Intent intent = new Intent(this, isSuw
|
||||||
? SetupFingerprintEnrollEnrolling.class
|
? SetupFingerprintEnrollFindSensor.class
|
||||||
: FingerprintEnrollFindSensor.class);
|
: FingerprintEnrollFindSensor.class);
|
||||||
intent.putExtras(mAutoCredentialViewModel.getCredentialBundle());
|
intent.putExtras(mAutoCredentialViewModel.getCredentialIntentExtra());
|
||||||
intent.putExtras(mViewModel.getNextActivityBaseIntentExtras());
|
intent.putExtras(mViewModel.getNextActivityBaseIntentExtras());
|
||||||
mNextActivityLauncher.launch(intent);
|
mNextActivityLauncher.launch(intent);
|
||||||
}
|
}
|
||||||
@@ -272,5 +278,6 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
|||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
mViewModel.onSaveInstanceState(outState);
|
mViewModel.onSaveInstanceState(outState);
|
||||||
|
mAutoCredentialViewModel.onSaveInstanceState(outState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,20 +30,21 @@ import android.app.Application;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
import androidx.activity.result.ActivityResult;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
import com.android.internal.widget.VerifyCredentialResponse;
|
import com.android.internal.widget.VerifyCredentialResponse;
|
||||||
import com.android.settings.biometrics.BiometricUtils;
|
import com.android.settings.biometrics.BiometricUtils;
|
||||||
|
import com.android.settings.biometrics.BiometricUtils.GatekeeperCredentialNotMatchException;
|
||||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
||||||
import com.android.settings.biometrics2.ui.model.CredentialModel;
|
import com.android.settings.biometrics2.ui.model.CredentialModel;
|
||||||
import com.android.settings.password.ChooseLockGeneric;
|
import com.android.settings.password.ChooseLockGeneric;
|
||||||
@@ -57,31 +58,40 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
* AutoCredentialViewModel which uses CredentialModel to determine next actions for activity, like
|
* AutoCredentialViewModel which uses CredentialModel to determine next actions for activity, like
|
||||||
* start ChooseLockActivity, start ConfirmLockActivity, GenerateCredential, or do nothing.
|
* start ChooseLockActivity, start ConfirmLockActivity, GenerateCredential, or do nothing.
|
||||||
*/
|
*/
|
||||||
public class AutoCredentialViewModel extends AndroidViewModel implements DefaultLifecycleObserver {
|
public class AutoCredentialViewModel extends AndroidViewModel {
|
||||||
|
|
||||||
private static final String TAG = "AutoCredentialViewModel";
|
private static final String TAG = "AutoCredentialViewModel";
|
||||||
private static final boolean DEBUG = true;
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String KEY_CREDENTIAL_MODEL = "credential_model";
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valid credential, activity doesn't need to do anything.
|
||||||
|
*/
|
||||||
|
public static final int CREDENTIAL_VALID = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This credential looks good, but still need to run generateChallenge().
|
||||||
|
*/
|
||||||
|
public static final int CREDENTIAL_IS_GENERATING_CHALLENGE = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Need activity to run choose lock
|
* Need activity to run choose lock
|
||||||
*/
|
*/
|
||||||
public static final int CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK = 1;
|
public static final int CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Need activity to run confirm lock
|
* Need activity to run confirm lock
|
||||||
*/
|
*/
|
||||||
public static final int CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK = 2;
|
public static final int CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK = 3;
|
||||||
|
|
||||||
/**
|
|
||||||
* Fail to use challenge from hardware generateChallenge(), shall finish activity with proper
|
|
||||||
* error code
|
|
||||||
*/
|
|
||||||
public static final int CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE = 3;
|
|
||||||
|
|
||||||
@IntDef(prefix = { "CREDENTIAL_" }, value = {
|
@IntDef(prefix = { "CREDENTIAL_" }, value = {
|
||||||
|
CREDENTIAL_VALID,
|
||||||
|
CREDENTIAL_IS_GENERATING_CHALLENGE,
|
||||||
CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK,
|
CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK,
|
||||||
CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK,
|
CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK
|
||||||
CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE
|
|
||||||
})
|
})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface CredentialAction {}
|
public @interface CredentialAction {}
|
||||||
@@ -157,11 +167,10 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NonNull private final LockPatternUtils mLockPatternUtils;
|
@NonNull private final LockPatternUtils mLockPatternUtils;
|
||||||
@NonNull private final ChallengeGenerator mChallengeGenerator;
|
@NonNull private final ChallengeGenerator mChallengeGenerator;
|
||||||
private CredentialModel mCredentialModel = null;
|
private CredentialModel mCredentialModel = null;
|
||||||
@NonNull private final MutableLiveData<Integer> mActionLiveData =
|
@NonNull private final MutableLiveData<Boolean> mGenerateChallengeFailLiveData =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
|
|
||||||
public AutoCredentialViewModel(
|
public AutoCredentialViewModel(
|
||||||
@@ -173,51 +182,63 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
|||||||
mChallengeGenerator = challengeGenerator;
|
mChallengeGenerator = challengeGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCredentialModel(@NonNull CredentialModel credentialModel) {
|
/**
|
||||||
mCredentialModel = credentialModel;
|
* Set CredentialModel, the source is coming from savedInstanceState or activity intent
|
||||||
|
*/
|
||||||
|
public void setCredentialModel(@Nullable Bundle savedInstanceState, @NonNull Intent intent) {
|
||||||
|
mCredentialModel = new CredentialModel(
|
||||||
|
savedInstanceState != null
|
||||||
|
? savedInstanceState.getBundle(KEY_CREDENTIAL_MODEL)
|
||||||
|
: intent.getExtras(),
|
||||||
|
SystemClock.elapsedRealtimeClock());
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "setCredentialModel " + mCredentialModel + ", savedInstanceState exist:"
|
||||||
|
+ (savedInstanceState != null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observe ActionLiveData for actions about choosing lock, confirming lock, or finishing
|
* Handle onSaveInstanceState from activity
|
||||||
* activity
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
public LiveData<Integer> getActionLiveData() {
|
outState.putBundle(KEY_CREDENTIAL_MODEL, mCredentialModel.getBundle());
|
||||||
return mActionLiveData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@NonNull
|
||||||
public void onCreate(@NonNull LifecycleOwner owner) {
|
public LiveData<Boolean> getGenerateChallengeFailLiveData() {
|
||||||
checkCredential();
|
return mGenerateChallengeFailLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check credential status for biometric enrollment.
|
* Check credential status for biometric enrollment.
|
||||||
*/
|
*/
|
||||||
private void checkCredential() {
|
@CredentialAction
|
||||||
|
public int checkCredential() {
|
||||||
if (isValidCredential()) {
|
if (isValidCredential()) {
|
||||||
return;
|
return CREDENTIAL_VALID;
|
||||||
}
|
}
|
||||||
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
||||||
if (isUnspecifiedPassword()) {
|
if (isUnspecifiedPassword()) {
|
||||||
mActionLiveData.postValue(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
return CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK;
|
||||||
} else if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
} else if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
||||||
generateChallenge(gkPwHandle);
|
generateChallenge(gkPwHandle);
|
||||||
|
return CREDENTIAL_IS_GENERATING_CHALLENGE;
|
||||||
} else {
|
} else {
|
||||||
mActionLiveData.postValue(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
return CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateChallenge(long gkPwHandle) {
|
private void generateChallenge(long gkPwHandle) {
|
||||||
mChallengeGenerator.setCallback((sensorId, userId, challenge) -> {
|
mChallengeGenerator.setCallback((sensorId, userId, challenge) -> {
|
||||||
mCredentialModel.setSensorId(sensorId);
|
|
||||||
mCredentialModel.setChallenge(challenge);
|
|
||||||
try {
|
try {
|
||||||
final byte[] newToken = requestGatekeeperHat(gkPwHandle, challenge, userId);
|
final byte[] newToken = requestGatekeeperHat(gkPwHandle, challenge, userId);
|
||||||
|
mCredentialModel.setSensorId(sensorId);
|
||||||
|
mCredentialModel.setChallenge(challenge);
|
||||||
mCredentialModel.setToken(newToken);
|
mCredentialModel.setToken(newToken);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
Log.e(TAG, "generateChallenge, IllegalStateException", e);
|
Log.e(TAG, "generateChallenge, IllegalStateException", e);
|
||||||
mActionLiveData.postValue(CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE);
|
mGenerateChallengeFailLiveData.postValue(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +252,7 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
|||||||
// Check credential again
|
// Check credential again
|
||||||
if (!isValidCredential()) {
|
if (!isValidCredential()) {
|
||||||
Log.w(TAG, "generateChallenge, invalid Credential");
|
Log.w(TAG, "generateChallenge, invalid Credential");
|
||||||
mActionLiveData.postValue(CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE);
|
mGenerateChallengeFailLiveData.postValue(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mChallengeGenerator.generateChallenge(getUserId());
|
mChallengeGenerator.generateChallenge(getUserId());
|
||||||
@@ -282,16 +303,16 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
|||||||
final VerifyCredentialResponse response = mLockPatternUtils
|
final VerifyCredentialResponse response = mLockPatternUtils
|
||||||
.verifyGatekeeperPasswordHandle(gkPwHandle, challenge, userId);
|
.verifyGatekeeperPasswordHandle(gkPwHandle, challenge, userId);
|
||||||
if (!response.isMatched()) {
|
if (!response.isMatched()) {
|
||||||
throw new IllegalStateException("Unable to request Gatekeeper HAT");
|
throw new GatekeeperCredentialNotMatchException("Unable to request Gatekeeper HAT");
|
||||||
}
|
}
|
||||||
return response.getGatekeeperHAT();
|
return response.getGatekeeperHAT();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Credential bundle which will be used to launch next activity.
|
* Get Credential intent extra which will be used to launch next activity.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public Bundle getCredentialBundle() {
|
public Bundle getCredentialIntentExtra() {
|
||||||
final Bundle retBundle = new Bundle();
|
final Bundle retBundle = new Bundle();
|
||||||
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
||||||
if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
||||||
|
|||||||
@@ -144,6 +144,13 @@ public class FingerprintEnrollIntroViewModel extends AndroidViewModel
|
|||||||
return mPageStatusLiveData;
|
return mPageStatusLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear user's action live data (like clicking Agree, Skip, or Done)
|
||||||
|
*/
|
||||||
|
public void clearActionLiveData() {
|
||||||
|
mActionLiveData.setValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user's action live data (like clicking Agree, Skip, or Done)
|
* Get user's action live data (like clicking Agree, Skip, or Done)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
|
||||||
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class CredentialModelTest {
|
||||||
|
|
||||||
|
private final Clock mClock = SystemClock.elapsedRealtimeClock();
|
||||||
|
|
||||||
|
public static Bundle newCredentialModelIntentExtras(int userId, long challenge, int sensorId,
|
||||||
|
@Nullable byte[] token, long gkPwHandle) {
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt(Intent.EXTRA_USER_ID, userId);
|
||||||
|
bundle.putInt(EXTRA_KEY_SENSOR_ID, sensorId);
|
||||||
|
bundle.putLong(EXTRA_KEY_CHALLENGE, challenge);
|
||||||
|
bundle.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
|
||||||
|
bundle.putLong(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bundle newValidTokenCredentialIntentExtras(int userId) {
|
||||||
|
return newCredentialModelIntentExtras(userId, 1L, 1, new byte[] { 0 }, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bundle newInvalidChallengeCredentialIntentExtras(int userId) {
|
||||||
|
return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bundle newGkPwHandleCredentialIntentExtras(int userId, long gkPwHandle) {
|
||||||
|
return newCredentialModelIntentExtras(userId, INVALID_CHALLENGE, 1, null, gkPwHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkBundleLongValue(@NonNull Bundle bundle1, @NonNull Bundle bundle2,
|
||||||
|
@NonNull String key) {
|
||||||
|
if (!bundle1.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int value1 = bundle1.getInt(key);
|
||||||
|
final int value2 = bundle2.getInt(key);
|
||||||
|
assertWithMessage("bundle not match, key:" + key + ", value1:" + value1 + ", value2:"
|
||||||
|
+ value2).that(value1).isEqualTo(value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkBundleIntValue(@NonNull Bundle bundle1, @NonNull Bundle bundle2,
|
||||||
|
@NonNull String key) {
|
||||||
|
if (!bundle1.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long value1 = bundle1.getLong(key);
|
||||||
|
final long value2 = bundle2.getLong(key);
|
||||||
|
assertWithMessage("bundle not match, key:" + key + ", value1:" + value1 + ", value2:"
|
||||||
|
+ value2).that(value1).isEqualTo(value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkBundleByteArrayValue(@NonNull Bundle bundle1, @NonNull Bundle bundle2,
|
||||||
|
@NonNull String key) {
|
||||||
|
if (!bundle1.containsKey(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final byte[] value1 = bundle1.getByteArray(key);
|
||||||
|
final byte[] value2 = bundle2.getByteArray(key);
|
||||||
|
final String errMsg = "bundle not match, key:" + key + ", value1:" + Arrays.toString(value1)
|
||||||
|
+ ", value2:" + Arrays.toString(value2);
|
||||||
|
if (value1 == null) {
|
||||||
|
assertWithMessage(errMsg).that(value2).isNull();
|
||||||
|
} else {
|
||||||
|
assertWithMessage(errMsg).that(value1.length).isEqualTo(value2.length);
|
||||||
|
for (int i = 0; i < value1.length; ++i) {
|
||||||
|
assertWithMessage(errMsg).that(value1[i]).isEqualTo(value2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void verifySameCredentialModels(@NonNull CredentialModel model1,
|
||||||
|
@NonNull CredentialModel model2) {
|
||||||
|
|
||||||
|
assertThat(model1.getUserId()).isEqualTo(model2.getUserId());
|
||||||
|
assertThat(model1.getSensorId()).isEqualTo(model2.getSensorId());
|
||||||
|
assertThat(model1.getChallenge()).isEqualTo(model2.getChallenge());
|
||||||
|
assertThat(model1.getGkPwHandle()).isEqualTo(model2.getGkPwHandle());
|
||||||
|
|
||||||
|
final byte[] token1 = model1.getToken();
|
||||||
|
final byte[] token2 = model2.getToken();
|
||||||
|
if (token1 == null) {
|
||||||
|
assertThat(token2).isNull();
|
||||||
|
} else {
|
||||||
|
assertThat(token2).isNotNull();
|
||||||
|
assertThat(token1.length).isEqualTo(token2.length);
|
||||||
|
for (int i = 0; i < token1.length; ++i) {
|
||||||
|
assertThat(token1[i]).isEqualTo(token2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Bundle bundle1 = model1.getBundle();
|
||||||
|
final Bundle bundle2 = model2.getBundle();
|
||||||
|
final Set<String> keySet1 = bundle1.keySet();
|
||||||
|
assertThat(keySet1.equals(bundle2.keySet())).isTrue();
|
||||||
|
checkBundleIntValue(bundle1, bundle2, Intent.EXTRA_USER_ID);
|
||||||
|
checkBundleIntValue(bundle1, bundle2, EXTRA_KEY_SENSOR_ID);
|
||||||
|
checkBundleLongValue(bundle1, bundle2, EXTRA_KEY_CHALLENGE);
|
||||||
|
checkBundleByteArrayValue(bundle1, bundle2, EXTRA_KEY_CHALLENGE);
|
||||||
|
checkBundleLongValue(bundle1, bundle2, EXTRA_KEY_GK_PW_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sameValueFromBundle() {
|
||||||
|
final Bundle bundle = newCredentialModelIntentExtras(1234, 6677L, 1,
|
||||||
|
new byte[] { 33, 44, 55 }, 987654321);
|
||||||
|
|
||||||
|
final CredentialModel model1 = new CredentialModel(bundle, mClock);
|
||||||
|
final CredentialModel model2 = new CredentialModel(model1.getBundle(), mClock);
|
||||||
|
|
||||||
|
verifySameCredentialModels(model1, model2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sameValueFromBundle_nullToken() {
|
||||||
|
final Bundle bundle = newCredentialModelIntentExtras(22, 33L, 1, null, 21L);
|
||||||
|
|
||||||
|
final CredentialModel model1 = new CredentialModel(bundle, mClock);
|
||||||
|
final CredentialModel model2 = new CredentialModel(model1.getBundle(), mClock);
|
||||||
|
|
||||||
|
verifySameCredentialModels(model1, model2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,12 +24,22 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
|
|||||||
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
|
||||||
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
|
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
|
||||||
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
|
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
|
||||||
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_SENSOR_ID;
|
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_SENSOR_ID;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newCredentialModelIntentExtras;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newGkPwHandleCredentialIntentExtras;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newInvalidChallengeCredentialIntentExtras;
|
||||||
|
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newValidTokenCredentialIntentExtras;
|
||||||
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_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_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.AutoCredentialViewModel.ChallengeGenerator;
|
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.ChallengeGenerator;
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CredentialAction;
|
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CredentialAction;
|
||||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.GenerateChallengeCallback;
|
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.GenerateChallengeCallback;
|
||||||
|
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.KEY_CREDENTIAL_MODEL;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
|
||||||
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -38,12 +48,11 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.SystemClock;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
import androidx.activity.result.ActivityResult;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -68,7 +77,6 @@ public class AutoCredentialViewModelTest {
|
|||||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||||
|
|
||||||
@Mock private LifecycleOwner mLifecycleOwner;
|
|
||||||
@Mock private LockPatternUtils mLockPatternUtils;
|
@Mock private LockPatternUtils mLockPatternUtils;
|
||||||
private TestChallengeGenerator mChallengeGenerator = null;
|
private TestChallengeGenerator mChallengeGenerator = null;
|
||||||
private AutoCredentialViewModel mAutoCredentialViewModel;
|
private AutoCredentialViewModel mAutoCredentialViewModel;
|
||||||
@@ -82,142 +90,222 @@ public class AutoCredentialViewModelTest {
|
|||||||
mChallengeGenerator);
|
mChallengeGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CredentialModel newCredentialModel(int userId, long challenge,
|
private void setupGenerateChallenge(int userId, int newSensorId, long newChallenge) {
|
||||||
@Nullable byte[] token, long gkPwHandle) {
|
|
||||||
final Intent intent = new Intent();
|
|
||||||
intent.putExtra(Intent.EXTRA_USER_ID, userId);
|
|
||||||
intent.putExtra(EXTRA_KEY_SENSOR_ID, 1);
|
|
||||||
intent.putExtra(EXTRA_KEY_CHALLENGE, challenge);
|
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
|
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
|
||||||
return new CredentialModel(intent, SystemClock.elapsedRealtimeClock());
|
|
||||||
}
|
|
||||||
|
|
||||||
private CredentialModel newValidTokenCredentialModel(int userId) {
|
|
||||||
return newCredentialModel(userId, 1L, new byte[] { 0 }, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CredentialModel newInvalidChallengeCredentialModel(int userId) {
|
|
||||||
return newCredentialModel(userId, INVALID_CHALLENGE, null, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CredentialModel newGkPwHandleCredentialModel(int userId, long gkPwHandle) {
|
|
||||||
return newCredentialModel(userId, INVALID_CHALLENGE, null, gkPwHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyNothingHappen() {
|
|
||||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyOnlyActionLiveData(@CredentialAction int action) {
|
|
||||||
final Integer value = mAutoCredentialViewModel.getActionLiveData().getValue();
|
|
||||||
assertThat(value).isEqualTo(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupGenerateTokenFlow(long gkPwHandle, int userId, int newSensorId,
|
|
||||||
long newChallenge) {
|
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
mChallengeGenerator.mUserId = userId;
|
mChallengeGenerator.mUserId = userId;
|
||||||
mChallengeGenerator.mSensorId = newSensorId;
|
mChallengeGenerator.mSensorId = newSensorId;
|
||||||
mChallengeGenerator.mChallenge = newChallenge;
|
mChallengeGenerator.mChallenge = newChallenge;
|
||||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
|
||||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_validCredentialCase() {
|
public void testGetCredentialIntentExtra_sameResultFromSavedInstanceOrIntent() {
|
||||||
|
final Bundle extras = newCredentialModelIntentExtras(12, 33, 1, new byte[] { 2, 3 }, 3L);
|
||||||
|
|
||||||
|
AutoCredentialViewModel autoCredentialViewModel2 = new AutoCredentialViewModel(
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
mLockPatternUtils,
|
||||||
|
mChallengeGenerator);
|
||||||
|
|
||||||
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(extras));
|
||||||
|
final Bundle savedInstance = new Bundle();
|
||||||
|
savedInstance.putBundle(KEY_CREDENTIAL_MODEL, extras);
|
||||||
|
autoCredentialViewModel2.setCredentialModel(savedInstance, new Intent());
|
||||||
|
|
||||||
|
final Bundle bundle1 = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||||
|
final Bundle bundle2 = autoCredentialViewModel2.getCredentialIntentExtra();
|
||||||
|
assertThat(bundle1.getLong(EXTRA_KEY_GK_PW_HANDLE))
|
||||||
|
.isEqualTo(bundle2.getLong(EXTRA_KEY_GK_PW_HANDLE));
|
||||||
|
assertThat(bundle1.getLong(Intent.EXTRA_USER_ID))
|
||||||
|
.isEqualTo(bundle2.getLong(Intent.EXTRA_USER_ID));
|
||||||
|
assertThat(bundle1.getLong(EXTRA_KEY_CHALLENGE))
|
||||||
|
.isEqualTo(bundle2.getLong(EXTRA_KEY_CHALLENGE));
|
||||||
|
assertThat(bundle1.getInt(EXTRA_KEY_SENSOR_ID))
|
||||||
|
.isEqualTo(bundle2.getInt(EXTRA_KEY_SENSOR_ID));
|
||||||
|
final byte[] token1 = bundle1.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||||
|
final byte[] token2 = bundle2.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||||
|
assertThat(token1).isNotNull();
|
||||||
|
assertThat(token2).isNotNull();
|
||||||
|
assertThat(token1.length).isEqualTo(token2.length);
|
||||||
|
for (int i = 0; i < token2.length; ++i) {
|
||||||
|
assertThat(token1[i]).isEqualTo(token2[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCredentialIntentExtra_sameResultFromSavedInstanceOrIntent_invalidValues() {
|
||||||
|
final Bundle extras = newCredentialModelIntentExtras(UserHandle.USER_NULL,
|
||||||
|
INVALID_CHALLENGE, INVALID_SENSOR_ID, null, INVALID_GK_PW_HANDLE);
|
||||||
|
|
||||||
|
AutoCredentialViewModel autoCredentialViewModel2 = new AutoCredentialViewModel(
|
||||||
|
ApplicationProvider.getApplicationContext(),
|
||||||
|
mLockPatternUtils,
|
||||||
|
mChallengeGenerator);
|
||||||
|
|
||||||
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(extras));
|
||||||
|
final Bundle savedInstance = new Bundle();
|
||||||
|
savedInstance.putBundle(KEY_CREDENTIAL_MODEL, extras);
|
||||||
|
autoCredentialViewModel2.setCredentialModel(savedInstance, new Intent());
|
||||||
|
|
||||||
|
final Bundle bundle1 = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||||
|
final Bundle bundle2 = autoCredentialViewModel2.getCredentialIntentExtra();
|
||||||
|
assertThat(bundle1.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
|
||||||
|
assertThat(bundle2.containsKey(EXTRA_KEY_GK_PW_HANDLE)).isFalse();
|
||||||
|
assertThat(bundle1.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
|
||||||
|
assertThat(bundle2.containsKey(EXTRA_KEY_CHALLENGE_TOKEN)).isFalse();
|
||||||
|
assertThat(bundle1.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
|
||||||
|
assertThat(bundle2.containsKey(EXTRA_KEY_SENSOR_ID)).isTrue();
|
||||||
|
assertThat(bundle1.containsKey(Intent.EXTRA_USER_ID)).isFalse();
|
||||||
|
assertThat(bundle2.containsKey(Intent.EXTRA_USER_ID)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckCredential_validCredentialCase() {
|
||||||
final int userId = 99;
|
final int userId = 99;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newValidTokenCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newValidTokenCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
verifyNothingHappen();
|
assertThat(action).isEqualTo(CREDENTIAL_VALID);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_needToChooseLock() {
|
public void testCheckCredential_needToChooseLock() {
|
||||||
final int userId = 100;
|
final int userId = 100;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_UNSPECIFIED);
|
PASSWORD_QUALITY_UNSPECIFIED);
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_needToConfirmLockFoSomething() {
|
public void testCheckCredential_needToConfirmLockFoSomething() {
|
||||||
final int userId = 101;
|
final int userId = 101;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_needToConfirmLockForNumeric() {
|
public void testCheckCredential_needToConfirmLockForNumeric() {
|
||||||
final int userId = 102;
|
final int userId = 102;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_NUMERIC);
|
PASSWORD_QUALITY_NUMERIC);
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_needToConfirmLockForAlphabetic() {
|
public void testCheckCredential_needToConfirmLockForAlphabetic() {
|
||||||
final int userId = 103;
|
final int userId = 103;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_ALPHABETIC);
|
PASSWORD_QUALITY_ALPHABETIC);
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void checkCredential_generateChallenge() {
|
public void testCheckCredential_generateChallenge() {
|
||||||
final int userId = 104;
|
final int userId = 104;
|
||||||
final long gkPwHandle = 1111L;
|
final long gkPwHandle = 1111L;
|
||||||
final CredentialModel credentialModel = newGkPwHandleCredentialModel(userId, gkPwHandle);
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
final int newSensorId = 10;
|
final int newSensorId = 10;
|
||||||
final long newChallenge = 20L;
|
final long newChallenge = 20L;
|
||||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||||
|
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||||
|
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||||
|
|
||||||
// Run credential check
|
// Run credential check
|
||||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
assertThat(action).isEqualTo(CREDENTIAL_IS_GENERATING_CHALLENGE);
|
||||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
|
||||||
|
assertThat(CredentialModel.isValidToken(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)))
|
||||||
|
.isTrue();
|
||||||
|
assertThat(CredentialModel.isValidGkPwHandle(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)))
|
||||||
|
.isFalse();
|
||||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetUserId() {
|
public void testCheckCredential_generateChallengeFail() {
|
||||||
|
final int userId = 104;
|
||||||
|
final long gkPwHandle = 1111L;
|
||||||
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||||
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
|
final int newSensorId = 10;
|
||||||
|
final long newChallenge = 20L;
|
||||||
|
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||||
|
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||||
|
.thenReturn(newBadCredential(0));
|
||||||
|
|
||||||
|
// Run credential check
|
||||||
|
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||||
|
|
||||||
|
assertThat(action).isEqualTo(CREDENTIAL_IS_GENERATING_CHALLENGE);
|
||||||
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isTrue();
|
||||||
|
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUserId_fromIntent() {
|
||||||
final int userId = 106;
|
final int userId = 106;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
|
|
||||||
|
// Get userId
|
||||||
|
assertThat(mAutoCredentialViewModel.getUserId()).isEqualTo(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUserId_fromSavedInstance() {
|
||||||
|
final int userId = 106;
|
||||||
|
final Bundle savedInstance = new Bundle();
|
||||||
|
savedInstance.putBundle(KEY_CREDENTIAL_MODEL,
|
||||||
|
newInvalidChallengeCredentialIntentExtras(userId));
|
||||||
|
mAutoCredentialViewModel.setCredentialModel(savedInstance, new Intent());
|
||||||
|
|
||||||
// Get userId
|
// Get userId
|
||||||
assertThat(mAutoCredentialViewModel.getUserId()).isEqualTo(userId);
|
assertThat(mAutoCredentialViewModel.getUserId()).isEqualTo(userId);
|
||||||
@@ -227,8 +315,8 @@ public class AutoCredentialViewModelTest {
|
|||||||
public void testCheckNewCredentialFromActivityResult_invalidChooseLock() {
|
public void testCheckNewCredentialFromActivityResult_invalidChooseLock() {
|
||||||
final int userId = 107;
|
final int userId = 107;
|
||||||
final long gkPwHandle = 3333L;
|
final long gkPwHandle = 3333L;
|
||||||
mAutoCredentialViewModel.setCredentialModel(
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||||
|
|
||||||
@@ -237,15 +325,15 @@ public class AutoCredentialViewModelTest {
|
|||||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent));
|
new ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent));
|
||||||
|
|
||||||
assertThat(ret).isFalse();
|
assertThat(ret).isFalse();
|
||||||
verifyNothingHappen();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckNewCredentialFromActivityResult_invalidConfirmLock() {
|
public void testCheckNewCredentialFromActivityResult_invalidConfirmLock() {
|
||||||
final int userId = 107;
|
final int userId = 107;
|
||||||
final long gkPwHandle = 3333L;
|
final long gkPwHandle = 3333L;
|
||||||
mAutoCredentialViewModel.setCredentialModel(
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||||
|
|
||||||
@@ -254,62 +342,68 @@ public class AutoCredentialViewModelTest {
|
|||||||
new ActivityResult(Activity.RESULT_OK + 1, intent));
|
new ActivityResult(Activity.RESULT_OK + 1, intent));
|
||||||
|
|
||||||
assertThat(ret).isFalse();
|
assertThat(ret).isFalse();
|
||||||
verifyNothingHappen();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckNewCredentialFromActivityResult_nullDataChooseLock() {
|
public void testCheckNewCredentialFromActivityResult_nullDataChooseLock() {
|
||||||
final int userId = 108;
|
final int userId = 108;
|
||||||
final long gkPwHandle = 4444L;
|
final long gkPwHandle = 4444L;
|
||||||
mAutoCredentialViewModel.setCredentialModel(
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||||
|
|
||||||
// run checkNewCredentialFromActivityResult()
|
// run checkNewCredentialFromActivityResult()
|
||||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, null));
|
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, null));
|
||||||
|
|
||||||
assertThat(ret).isFalse();
|
assertThat(ret).isFalse();
|
||||||
verifyNothingHappen();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckNewCredentialFromActivityResult_nullDataConfirmLock() {
|
public void testCheckNewCredentialFromActivityResult_nullDataConfirmLock() {
|
||||||
final int userId = 109;
|
final int userId = 109;
|
||||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
|
|
||||||
// run checkNewCredentialFromActivityResult()
|
// run checkNewCredentialFromActivityResult()
|
||||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||||
new ActivityResult(Activity.RESULT_OK, null));
|
new ActivityResult(Activity.RESULT_OK, null));
|
||||||
|
|
||||||
assertThat(ret).isFalse();
|
assertThat(ret).isFalse();
|
||||||
verifyNothingHappen();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckNewCredentialFromActivityResult_validChooseLock() {
|
public void testCheckNewCredentialFromActivityResult_validChooseLock() {
|
||||||
final int userId = 108;
|
final int userId = 108;
|
||||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
final long gkPwHandle = 6666L;
|
final long gkPwHandle = 6666L;
|
||||||
final int newSensorId = 50;
|
final int newSensorId = 50;
|
||||||
final long newChallenge = 60L;
|
final long newChallenge = 60L;
|
||||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||||
final Intent intent = new Intent();
|
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||||
|
|
||||||
// Run checkNewCredentialFromActivityResult()
|
// Run checkNewCredentialFromActivityResult()
|
||||||
|
final Intent intent = new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||||
|
gkPwHandle);
|
||||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, intent));
|
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, intent));
|
||||||
|
|
||||||
assertThat(ret).isTrue();
|
assertThat(ret).isTrue();
|
||||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
|
||||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
assertThat(CredentialModel.isValidToken(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)))
|
||||||
|
.isTrue();
|
||||||
|
assertThat(CredentialModel.isValidGkPwHandle(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)))
|
||||||
|
.isFalse();
|
||||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,28 +411,33 @@ public class AutoCredentialViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testCheckNewCredentialFromActivityResult_validConfirmLock() {
|
public void testCheckNewCredentialFromActivityResult_validConfirmLock() {
|
||||||
final int userId = 109;
|
final int userId = 109;
|
||||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
mAutoCredentialViewModel.setCredentialModel(null,
|
||||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||||
PASSWORD_QUALITY_SOMETHING);
|
PASSWORD_QUALITY_SOMETHING);
|
||||||
|
|
||||||
final long gkPwHandle = 5555L;
|
final long gkPwHandle = 5555L;
|
||||||
final int newSensorId = 80;
|
final int newSensorId = 80;
|
||||||
final long newChallenge = 90L;
|
final long newChallenge = 90L;
|
||||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||||
final Intent intent = new Intent();
|
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||||
|
|
||||||
// Run checkNewCredentialFromActivityResult()
|
// Run checkNewCredentialFromActivityResult()
|
||||||
|
final Intent intent = new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||||
|
gkPwHandle);
|
||||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||||
new ActivityResult(Activity.RESULT_OK, intent));
|
new ActivityResult(Activity.RESULT_OK, intent));
|
||||||
|
|
||||||
assertThat(ret).isTrue();
|
assertThat(ret).isTrue();
|
||||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
assertThat(extras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
|
||||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
assertThat(CredentialModel.isValidToken(extras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN)))
|
||||||
|
.isTrue();
|
||||||
|
assertThat(CredentialModel.isValidGkPwHandle(extras.getLong(EXTRA_KEY_GK_PW_HANDLE)))
|
||||||
|
.isFalse();
|
||||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,4 +476,12 @@ public class AutoCredentialViewModelTest {
|
|||||||
.setGatekeeperHAT(hat)
|
.setGatekeeperHAT(hat)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VerifyCredentialResponse newBadCredential(int timeout) {
|
||||||
|
if (timeout > 0) {
|
||||||
|
return VerifyCredentialResponse.fromTimeout(timeout);
|
||||||
|
} else {
|
||||||
|
return VerifyCredentialResponse.fromError();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import android.hardware.fingerprint.FingerprintManager;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -92,6 +93,18 @@ public class FingerprintEnrollIntroViewModelTest {
|
|||||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_UNKNOWN);
|
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClearActionLiveData() {
|
||||||
|
final MutableLiveData<Integer> actionLiveData =
|
||||||
|
(MutableLiveData<Integer>) mViewModel.getActionLiveData();
|
||||||
|
actionLiveData.postValue(1);
|
||||||
|
assertThat(actionLiveData.getValue()).isEqualTo(1);
|
||||||
|
|
||||||
|
mViewModel.clearActionLiveData();
|
||||||
|
|
||||||
|
assertThat(actionLiveData.getValue()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetEnrollmentRequest() {
|
public void testGetEnrollmentRequest() {
|
||||||
final EnrollmentRequest request = newAllFalseRequest(mApplication);
|
final EnrollmentRequest request = newAllFalseRequest(mApplication);
|
||||||
|
|||||||
Reference in New Issue
Block a user