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 android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -80,17 +81,30 @@ public final class CredentialModel {
|
||||
@Nullable
|
||||
private Long mClearGkPwHandleMillis = null;
|
||||
|
||||
public CredentialModel(@NonNull Intent intent, @NonNull Clock clock) {
|
||||
mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||
mSensorId = intent.getIntExtra(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
|
||||
mChallenge = intent.getLongExtra(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
|
||||
mToken = intent.getByteArrayExtra(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
mGkPwHandle = intent.getLongExtra(EXTRA_KEY_GK_PW_HANDLE,
|
||||
INVALID_GK_PW_HANDLE);
|
||||
public CredentialModel(@NonNull Bundle bundle, @NonNull Clock clock) {
|
||||
mUserId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||
mSensorId = bundle.getInt(EXTRA_KEY_SENSOR_ID, INVALID_SENSOR_ID);
|
||||
mChallenge = bundle.getLong(EXTRA_KEY_CHALLENGE, INVALID_CHALLENGE);
|
||||
mToken = bundle.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
mGkPwHandle = bundle.getLong(EXTRA_KEY_GK_PW_HANDLE, INVALID_GK_PW_HANDLE);
|
||||
mClock = clock;
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,7 @@ import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroSt
|
||||
import static com.google.android.setupdesign.util.DynamicColorPalette.ColorType.ACCENT;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyResourcesManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
@@ -63,9 +63,6 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "FingerprintEnrollIntroFragment";
|
||||
|
||||
@NonNull private final ViewModelProvider mViewModelProvider;
|
||||
@Nullable private final DevicePolicyResourcesManager mDevicePolicyMgrRes;
|
||||
|
||||
private FingerprintEnrollIntroViewModel mViewModel = null;
|
||||
|
||||
private View mView = null;
|
||||
@@ -75,12 +72,8 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
||||
private TextView mFooterMessage6 = null;
|
||||
@Nullable private PorterDuffColorFilter mIconColorFilter;
|
||||
|
||||
public FingerprintEnrollIntroFragment(
|
||||
@NonNull ViewModelProvider viewModelProvider,
|
||||
@Nullable DevicePolicyResourcesManager devicePolicyMgrRes) {
|
||||
public FingerprintEnrollIntroFragment() {
|
||||
super();
|
||||
mViewModelProvider = viewModelProvider;
|
||||
mDevicePolicyMgrRes = devicePolicyMgrRes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -197,7 +190,8 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
mViewModel = mViewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
||||
mViewModel = new ViewModelProvider(getActivity())
|
||||
.get(FingerprintEnrollIntroViewModel.class);
|
||||
getLifecycle().addObserver(mViewModel);
|
||||
super.onAttach(context);
|
||||
}
|
||||
@@ -232,12 +226,16 @@ public class FingerprintEnrollIntroFragment extends Fragment {
|
||||
private String getDescriptionDisabledByAdmin(@NonNull Context context) {
|
||||
final int defaultStrId =
|
||||
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");
|
||||
return "";
|
||||
}
|
||||
return mDevicePolicyMgrRes.getString(FINGERPRINT_UNLOCK_DISABLED,
|
||||
() -> context.getString(defaultStrId));
|
||||
}
|
||||
|
||||
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 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_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_DONE_AND_FINISH;
|
||||
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.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
@@ -42,7 +41,6 @@ import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.viewmodel.CreationExtras;
|
||||
import androidx.lifecycle.viewmodel.MutableCreationExtras;
|
||||
@@ -51,11 +49,9 @@ import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollBase;
|
||||
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.factory.BiometricsFragmentFactory;
|
||||
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;
|
||||
@@ -102,12 +98,12 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
getLifecycle().addObserver(mViewModel);
|
||||
|
||||
mAutoCredentialViewModel = viewModelProvider.get(AutoCredentialViewModel.class);
|
||||
mAutoCredentialViewModel.setCredentialModel(new CredentialModel(getIntent(),
|
||||
SystemClock.elapsedRealtimeClock()));
|
||||
getLifecycle().addObserver(mAutoCredentialViewModel);
|
||||
mAutoCredentialViewModel.setCredentialModel(savedInstanceState, getIntent());
|
||||
mAutoCredentialViewModel.getGenerateChallengeFailLiveData().observe(this,
|
||||
this::onGenerateChallengeFail);
|
||||
|
||||
mViewModel.getSetResultLiveData().observe(this, this::onSetActivityResult);
|
||||
mAutoCredentialViewModel.getActionLiveData().observe(this, this::onCredentialAction);
|
||||
checkCredential();
|
||||
|
||||
// Theme
|
||||
setTheme(mViewModel.getRequest().getTheme());
|
||||
@@ -116,21 +112,29 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
|
||||
// fragment
|
||||
setContentView(R.layout.biometric_enrollment_container);
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
fragmentManager.setFragmentFactory(
|
||||
new BiometricsFragmentFactory(getApplication(), viewModelProvider));
|
||||
|
||||
final FingerprintEnrollIntroViewModel fingerprintEnrollIntroViewModel =
|
||||
viewModelProvider.get(FingerprintEnrollIntroViewModel.class);
|
||||
fingerprintEnrollIntroViewModel.setEnrollmentRequest(mViewModel.getRequest());
|
||||
fingerprintEnrollIntroViewModel.setUserId(mAutoCredentialViewModel.getUserId());
|
||||
|
||||
// Clear ActionLiveData in FragmentViewModel to prevent getting previous action when
|
||||
// recreate
|
||||
fingerprintEnrollIntroViewModel.clearActionLiveData();
|
||||
fingerprintEnrollIntroViewModel.getActionLiveData().observe(
|
||||
this, this::observeIntroAction);
|
||||
final String tag = "FingerprintEnrollIntroFragment";
|
||||
fragmentManager.beginTransaction()
|
||||
.setReorderingAllowed(true)
|
||||
.add(R.id.fragment_container_view, FingerprintEnrollIntroFragment.class, null, tag)
|
||||
.commit();
|
||||
if (savedInstanceState == null) {
|
||||
final String tag = "FingerprintEnrollIntroFragment";
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.setReorderingAllowed(true)
|
||||
.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) {
|
||||
@@ -141,8 +145,8 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
finish();
|
||||
}
|
||||
|
||||
private void onCredentialAction(@NonNull Integer action) {
|
||||
switch (action) {
|
||||
private void checkCredential() {
|
||||
switch (mAutoCredentialViewModel.checkCredential()) {
|
||||
case CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK: {
|
||||
final Intent intent = mAutoCredentialViewModel.getChooseLockIntent(this,
|
||||
mViewModel.getRequest().isSuw(), mViewModel.getRequest().getSuwExtras());
|
||||
@@ -168,12 +172,9 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE: {
|
||||
Log.w(TAG, "observeCredentialLiveData, finish with action:" + action);
|
||||
if (mViewModel.getRequest().isAfterSuwOrSuwSuggestedAction()) {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
finish();
|
||||
case CREDENTIAL_VALID:
|
||||
case CREDENTIAL_IS_GENERATING_CHALLENGE: {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,10 +187,15 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
if (mAutoCredentialViewModel.checkNewCredentialFromActivityResult(
|
||||
isChooseLock, activityResult)) {
|
||||
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) {
|
||||
case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
|
||||
onSetActivityResult(
|
||||
@@ -207,9 +213,9 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
Log.w(TAG, "startNext, isSuw:" + isSuw + ", fail to set isWaiting flag");
|
||||
}
|
||||
final Intent intent = new Intent(this, isSuw
|
||||
? SetupFingerprintEnrollEnrolling.class
|
||||
? SetupFingerprintEnrollFindSensor.class
|
||||
: FingerprintEnrollFindSensor.class);
|
||||
intent.putExtras(mAutoCredentialViewModel.getCredentialBundle());
|
||||
intent.putExtras(mAutoCredentialViewModel.getCredentialIntentExtra());
|
||||
intent.putExtras(mViewModel.getNextActivityBaseIntentExtras());
|
||||
mNextActivityLauncher.launch(intent);
|
||||
}
|
||||
@@ -272,5 +278,6 @@ public class FingerprintEnrollmentActivity extends FragmentActivity {
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
mViewModel.onSaveInstanceState(outState);
|
||||
mAutoCredentialViewModel.onSaveInstanceState(outState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,20 +30,21 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
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.ui.model.CredentialModel;
|
||||
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
|
||||
* 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 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static final int CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK = 2;
|
||||
|
||||
/**
|
||||
* Fail to use challenge from hardware generateChallenge(), shall finish activity with proper
|
||||
* error code
|
||||
*/
|
||||
public static final int CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE = 3;
|
||||
public static final int CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK = 3;
|
||||
|
||||
@IntDef(prefix = { "CREDENTIAL_" }, value = {
|
||||
CREDENTIAL_VALID,
|
||||
CREDENTIAL_IS_GENERATING_CHALLENGE,
|
||||
CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK,
|
||||
CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK,
|
||||
CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE
|
||||
CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CredentialAction {}
|
||||
@@ -157,11 +167,10 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NonNull private final LockPatternUtils mLockPatternUtils;
|
||||
@NonNull private final ChallengeGenerator mChallengeGenerator;
|
||||
private CredentialModel mCredentialModel = null;
|
||||
@NonNull private final MutableLiveData<Integer> mActionLiveData =
|
||||
@NonNull private final MutableLiveData<Boolean> mGenerateChallengeFailLiveData =
|
||||
new MutableLiveData<>();
|
||||
|
||||
public AutoCredentialViewModel(
|
||||
@@ -173,51 +182,63 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
||||
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
|
||||
* activity
|
||||
* Handle onSaveInstanceState from activity
|
||||
*/
|
||||
@NonNull
|
||||
public LiveData<Integer> getActionLiveData() {
|
||||
return mActionLiveData;
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putBundle(KEY_CREDENTIAL_MODEL, mCredentialModel.getBundle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NonNull LifecycleOwner owner) {
|
||||
checkCredential();
|
||||
@NonNull
|
||||
public LiveData<Boolean> getGenerateChallengeFailLiveData() {
|
||||
return mGenerateChallengeFailLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check credential status for biometric enrollment.
|
||||
*/
|
||||
private void checkCredential() {
|
||||
@CredentialAction
|
||||
public int checkCredential() {
|
||||
if (isValidCredential()) {
|
||||
return;
|
||||
return CREDENTIAL_VALID;
|
||||
}
|
||||
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
||||
if (isUnspecifiedPassword()) {
|
||||
mActionLiveData.postValue(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
||||
return CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK;
|
||||
} else if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
||||
generateChallenge(gkPwHandle);
|
||||
return CREDENTIAL_IS_GENERATING_CHALLENGE;
|
||||
} else {
|
||||
mActionLiveData.postValue(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
return CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
|
||||
}
|
||||
}
|
||||
|
||||
private void generateChallenge(long gkPwHandle) {
|
||||
mChallengeGenerator.setCallback((sensorId, userId, challenge) -> {
|
||||
mCredentialModel.setSensorId(sensorId);
|
||||
mCredentialModel.setChallenge(challenge);
|
||||
try {
|
||||
final byte[] newToken = requestGatekeeperHat(gkPwHandle, challenge, userId);
|
||||
mCredentialModel.setSensorId(sensorId);
|
||||
mCredentialModel.setChallenge(challenge);
|
||||
mCredentialModel.setToken(newToken);
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "generateChallenge, IllegalStateException", e);
|
||||
mActionLiveData.postValue(CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE);
|
||||
mGenerateChallengeFailLiveData.postValue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,7 +252,7 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
||||
// Check credential again
|
||||
if (!isValidCredential()) {
|
||||
Log.w(TAG, "generateChallenge, invalid Credential");
|
||||
mActionLiveData.postValue(CREDENTIAL_FAIL_DURING_GENERATE_CHALLENGE);
|
||||
mGenerateChallengeFailLiveData.postValue(true);
|
||||
}
|
||||
});
|
||||
mChallengeGenerator.generateChallenge(getUserId());
|
||||
@@ -282,16 +303,16 @@ public class AutoCredentialViewModel extends AndroidViewModel implements Default
|
||||
final VerifyCredentialResponse response = mLockPatternUtils
|
||||
.verifyGatekeeperPasswordHandle(gkPwHandle, challenge, userId);
|
||||
if (!response.isMatched()) {
|
||||
throw new IllegalStateException("Unable to request Gatekeeper HAT");
|
||||
throw new GatekeeperCredentialNotMatchException("Unable to request Gatekeeper HAT");
|
||||
}
|
||||
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
|
||||
public Bundle getCredentialBundle() {
|
||||
public Bundle getCredentialIntentExtra() {
|
||||
final Bundle retBundle = new Bundle();
|
||||
final long gkPwHandle = mCredentialModel.getGkPwHandle();
|
||||
if (CredentialModel.isValidGkPwHandle(gkPwHandle)) {
|
||||
|
||||
@@ -144,6 +144,13 @@ public class FingerprintEnrollIntroViewModel extends AndroidViewModel
|
||||
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)
|
||||
*/
|
||||
|
||||
@@ -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_SENSOR_ID;
|
||||
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.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_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.CredentialAction;
|
||||
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;
|
||||
|
||||
@@ -38,12 +48,11 @@ import static org.mockito.Mockito.when;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
@@ -68,7 +77,6 @@ public class AutoCredentialViewModelTest {
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||
|
||||
@Mock private LifecycleOwner mLifecycleOwner;
|
||||
@Mock private LockPatternUtils mLockPatternUtils;
|
||||
private TestChallengeGenerator mChallengeGenerator = null;
|
||||
private AutoCredentialViewModel mAutoCredentialViewModel;
|
||||
@@ -82,142 +90,222 @@ public class AutoCredentialViewModelTest {
|
||||
mChallengeGenerator);
|
||||
}
|
||||
|
||||
private CredentialModel newCredentialModel(int userId, long challenge,
|
||||
@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) {
|
||||
private void setupGenerateChallenge(int userId, int newSensorId, long newChallenge) {
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
mChallengeGenerator.mUserId = userId;
|
||||
mChallengeGenerator.mSensorId = newSensorId;
|
||||
mChallengeGenerator.mChallenge = newChallenge;
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
}
|
||||
|
||||
@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;
|
||||
mAutoCredentialViewModel.setCredentialModel(newValidTokenCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newValidTokenCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||
|
||||
verifyNothingHappen();
|
||||
assertThat(action).isEqualTo(CREDENTIAL_VALID);
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_needToChooseLock() {
|
||||
public void testCheckCredential_needToChooseLock() {
|
||||
final int userId = 100;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_UNSPECIFIED);
|
||||
|
||||
// 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
|
||||
public void checkCredential_needToConfirmLockFoSomething() {
|
||||
public void testCheckCredential_needToConfirmLockFoSomething() {
|
||||
final int userId = 101;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// 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
|
||||
public void checkCredential_needToConfirmLockForNumeric() {
|
||||
public void testCheckCredential_needToConfirmLockForNumeric() {
|
||||
final int userId = 102;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_NUMERIC);
|
||||
|
||||
// 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
|
||||
public void checkCredential_needToConfirmLockForAlphabetic() {
|
||||
public void testCheckCredential_needToConfirmLockForAlphabetic() {
|
||||
final int userId = 103;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_ALPHABETIC);
|
||||
|
||||
// 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
|
||||
public void checkCredential_generateChallenge() {
|
||||
public void testCheckCredential_generateChallenge() {
|
||||
final int userId = 104;
|
||||
final long gkPwHandle = 1111L;
|
||||
final CredentialModel credentialModel = newGkPwHandleCredentialModel(userId, gkPwHandle);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
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;
|
||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
@CredentialAction final int action = mAutoCredentialViewModel.checkCredential();
|
||||
|
||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
||||
assertThat(action).isEqualTo(CREDENTIAL_IS_GENERATING_CHALLENGE);
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||
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);
|
||||
}
|
||||
|
||||
@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;
|
||||
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
|
||||
assertThat(mAutoCredentialViewModel.getUserId()).isEqualTo(userId);
|
||||
@@ -227,8 +315,8 @@ public class AutoCredentialViewModelTest {
|
||||
public void testCheckNewCredentialFromActivityResult_invalidChooseLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
@@ -237,15 +325,15 @@ public class AutoCredentialViewModelTest {
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_invalidConfirmLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
@@ -254,62 +342,68 @@ public class AutoCredentialViewModelTest {
|
||||
new ActivityResult(Activity.RESULT_OK + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataChooseLock() {
|
||||
final int userId = 108;
|
||||
final long gkPwHandle = 4444L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataConfirmLock() {
|
||||
final int userId = 109;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validChooseLock() {
|
||||
final int userId = 108;
|
||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final long gkPwHandle = 6666L;
|
||||
final int newSensorId = 50;
|
||||
final long newChallenge = 60L;
|
||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
final Intent intent = new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
gkPwHandle);
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, intent));
|
||||
|
||||
assertThat(ret).isTrue();
|
||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -317,28 +411,33 @@ public class AutoCredentialViewModelTest {
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validConfirmLock() {
|
||||
final int userId = 109;
|
||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
mAutoCredentialViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newInvalidChallengeCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final long gkPwHandle = 5555L;
|
||||
final int newSensorId = 80;
|
||||
final long newChallenge = 90L;
|
||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
final Intent intent = new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
gkPwHandle);
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK, intent));
|
||||
|
||||
assertThat(ret).isTrue();
|
||||
assertThat(mAutoCredentialViewModel.getActionLiveData().getValue()).isNull();
|
||||
assertThat(credentialModel.getSensorId()).isEqualTo(newSensorId);
|
||||
assertThat(credentialModel.getChallenge()).isEqualTo(newChallenge);
|
||||
assertThat(CredentialModel.isValidToken(credentialModel.getToken())).isTrue();
|
||||
assertThat(CredentialModel.isValidGkPwHandle(credentialModel.getGkPwHandle())).isFalse();
|
||||
assertThat(mAutoCredentialViewModel.getGenerateChallengeFailLiveData().getValue()).isNull();
|
||||
final Bundle extras = mAutoCredentialViewModel.getCredentialIntentExtra();
|
||||
assertThat(extras.getInt(EXTRA_KEY_SENSOR_ID)).isEqualTo(newSensorId);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -377,4 +476,12 @@ public class AutoCredentialViewModelTest {
|
||||
.setGatekeeperHAT(hat)
|
||||
.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.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
@@ -92,6 +93,18 @@ public class FingerprintEnrollIntroViewModelTest {
|
||||
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
|
||||
public void testGetEnrollmentRequest() {
|
||||
final EnrollmentRequest request = newAllFalseRequest(mApplication);
|
||||
|
||||
Reference in New Issue
Block a user