Fix FingerprintEnrollmentActivity rotaiton crash
1. When FragmentActivity rotated, FragmentManager will call default fragment constructor w/o parameters. Remove parameters of FingerprintEnrollIntroFragment constructor. And also remove BiometricsFragmentFactory because of useless now. 2. Remove some LiveData inside AutoCredentialViewModel because it causes jitter on activity transition. 3. Save and restore data inside AutoCredentialViewModel for handling activity recreation during rotation. 4. clear FingerprintEnrollIntroViewModel.mActionLiveData to prevent that activity gets previous action after recreate 5. Fix launching wrong activity during setupwizard Bug: 259626932 Test: atest AutoCredentialViewModelTest CredentialModelTest FingerprintEnrollIntroViewModelTest Change-Id: Ia26c86dc99ad91dbddef90538d9f5e5583585063
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)
|
||||
*/
|
||||
|
Reference in New Issue
Block a user