Merge "[Settings] Apply the SettingsDataService to the SIM page, MobileDataPreferenceController"
diff --git a/res/values/config.xml b/res/values/config.xml
index d7b2afa..e7efa6f 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -615,6 +615,9 @@
<item>android.uid.system:1000</item>
</string-array>
+ <!-- The default value for RedactionInterstitial in SUW -->
+ <bool name="default_allow_sensitive_lockscreen_content">true</bool>
+
<!-- Whether to enable the app battery usage list page feature. -->
<bool name="config_app_battery_usage_list_enabled">false</bool>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2dc4e65..0fd9617 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10486,8 +10486,8 @@
<!-- Title for the button to reboot with MTE enabled. [CHAR LIMIT=NONE] -->
<string name="reboot_with_mte_title">Reboot with MTE</string>
<string name="reboot_with_mte_message">System will reboot and allow to experiment with Memory Tagging Extension (MTE). MTE may negatively impact system performance and stability. Will be reset on next subsequent reboot.</string>
- <string name="reboot_with_mte_summary">Try MTE for a single boot for app development.</string>
- <string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection.</string>
+ <string name="reboot_with_mte_summary">Try MTE for a single boot for app development</string>
+ <string name="reboot_with_mte_already_enabled">MTE is enabled through Advanced memory protection</string>
<!-- Toast that is shown when the user initiates capturing a heap dump for the system server. [CHAR LIMIT=NONE] -->
<string name="capturing_system_heap_dump_message">Capturing system heap dump</string>
<!-- Toast that is shown if there's an error capturing the user initiated heap dump. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/TrustedCredentialsFragment.java b/src/com/android/settings/TrustedCredentialsFragment.java
index ca565a4..c90a44d 100644
--- a/src/com/android/settings/TrustedCredentialsFragment.java
+++ b/src/com/android/settings/TrustedCredentialsFragment.java
@@ -25,7 +25,6 @@
import android.app.Activity;
import android.app.KeyguardManager;
import android.app.admin.DevicePolicyManager;
-import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -68,7 +67,7 @@
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.TrustedCredentialsSettings.Tab;
-import com.android.settings.core.InstrumentedFragment;
+import com.android.settingslib.core.lifecycle.ObservableFragment;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
@@ -81,7 +80,7 @@
/**
* Fragment to display trusted credentials settings for one tab.
*/
-public class TrustedCredentialsFragment extends InstrumentedFragment
+public class TrustedCredentialsFragment extends ObservableFragment
implements TrustedCredentialsDialogBuilder.DelegateInterface {
public static final String ARG_POSITION = "tab";
@@ -176,11 +175,6 @@
return mFragmentView;
}
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.TRUSTED_CREDENTIALS;
- }
-
private void createChildView(
LayoutInflater inflater, ViewGroup parent, Bundle childState, int i) {
boolean isWork = mGroupAdapter.getUserInfoByGroup(i).isManagedProfile();
diff --git a/src/com/android/settings/applications/appinfo/WriteSettingsDetails.java b/src/com/android/settings/applications/appinfo/WriteSettingsDetails.java
index 4251346..d17f843 100644
--- a/src/com/android/settings/applications/appinfo/WriteSettingsDetails.java
+++ b/src/com/android/settings/applications/appinfo/WriteSettingsDetails.java
@@ -113,7 +113,7 @@
@Override
public int getMetricsCategory() {
- return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
+ return SettingsEnums.MODIFY_SYSTEM_SETTINGS;
}
public static CharSequence getSummary(Context context, AppEntry entry) {
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index fa5852e..4701d0d 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -527,7 +527,7 @@
case LIST_TYPE_OVERLAY:
return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
case LIST_TYPE_WRITE_SETTINGS:
- return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;
+ return SettingsEnums.MODIFY_SYSTEM_SETTINGS;
case LIST_TYPE_MANAGE_SOURCES:
return SettingsEnums.MANAGE_EXTERNAL_SOURCES;
case LIST_TYPE_WIFI_ACCESS:
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsFragmentFactory.java b/src/com/android/settings/biometrics2/factory/BiometricsFragmentFactory.java
deleted file mode 100644
index 9a0cab2..0000000
--- a/src/com/android/settings/biometrics2/factory/BiometricsFragmentFactory.java
+++ /dev/null
@@ -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);
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
index 06caf5e..b943608 100644
--- a/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
+++ b/src/com/android/settings/biometrics2/ui/model/CredentialModel.java
@@ -22,6 +22,7 @@
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,18 +81,31 @@
@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
*/
public int getUserId() {
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
index 2308f2e..14d859d 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.java
@@ -25,7 +25,7 @@
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 @@
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 @@
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 @@
@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 @@
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) {
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
index e9cf6fd..991aeba 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.java
@@ -19,20 +19,19 @@
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.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.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 @@
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 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mViewModel.onSaveInstanceState(outState);
+ mAutoCredentialViewModel.onSaveInstanceState(outState);
}
}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
index b1a7f90..a443e69 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.java
@@ -30,20 +30,21 @@
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 @@
* 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 @@
}
}
-
@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 @@
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 @@
// 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 @@
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)) {
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.java
index 252a508..3274eb2 100644
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.java
+++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.java
@@ -145,6 +145,13 @@
}
/**
+ * 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)
*/
public LiveData<Integer> getActionLiveData() {
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
index 7382299..0eca3a6 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
@@ -167,7 +167,7 @@
@Override
public int getMetricsCategory() {
- return 0;
+ return SettingsEnums.FUELGAUGE_BATTERY_SAVER_SCHEDULE;
}
private void logPowerSaver() {
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
index d4c00a4..5fd3905 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
@@ -43,7 +43,6 @@
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
-import java.text.NumberFormat;
import java.util.List;
/**
@@ -142,29 +141,6 @@
.setPositiveButton(R.string.battery_tip_unrestrict_app_dialog_ok, this)
.setNegativeButton(R.string.battery_tip_unrestrict_app_dialog_cancel, null)
.create();
- case BatteryTip.TipType.BATTERY_DEFENDER:
- mMetricsFeatureProvider.action(context,
- SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, mMetricsKey);
- final double chargeLimitLevel = 0.8f;
- final String percentage =
- NumberFormat.getPercentInstance().format(chargeLimitLevel);
- final String message = context.getString(
- R.string.battery_tip_limited_temporarily_dialog_msg, percentage);
- final boolean isPluggedIn = isPluggedIn();
- final AlertDialog.Builder dialogBuilder =
- new AlertDialog.Builder(context)
- .setTitle(R.string.battery_tip_limited_temporarily_title)
- .setMessage(message);
- if (isPluggedIn) {
- dialogBuilder
- .setPositiveButton(
- R.string.battery_tip_limited_temporarily_dialog_resume_charge,
- this)
- .setNegativeButton(R.string.okay, null);
- } else {
- dialogBuilder.setPositiveButton(R.string.okay, null);
- }
- return dialogBuilder.create();
default:
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
deleted file mode 100644
index 824b6be..0000000
--- a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 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.fuelgauge.batterytip.actions;
-
-import android.content.Intent;
-
-import com.android.settings.SettingsActivity;
-import com.android.settings.overlay.FeatureFactory;
-
-/**
- * Action to open the Support Center article
- */
-public class BatteryDefenderAction extends BatteryTipAction {
- private SettingsActivity mSettingsActivity;
-
- public BatteryDefenderAction(SettingsActivity settingsActivity) {
- super(settingsActivity.getApplicationContext());
- mSettingsActivity = settingsActivity;
- }
-
- @Override
- public void handlePositiveAction(int metricsKey) {
- final Intent intent = FeatureFactory.getFactory(mContext)
- .getPowerUsageFeatureProvider(mContext).getResumeChargeIntent();
- if (intent != null) {
- mContext.sendBroadcast(intent);
- }
- }
-}
diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java
index f243250..d6fdaf8 100644
--- a/src/com/android/settings/notification/RedactionInterstitial.java
+++ b/src/com/android/settings/notification/RedactionInterstitial.java
@@ -189,13 +189,16 @@
}
private void loadFromSettings() {
+ final boolean showUnRedactedDefault = getContext().getResources().getBoolean(
+ R.bool.default_allow_sensitive_lockscreen_content);
final boolean managedProfile = UserManager.get(getContext()).isManagedProfile(mUserId);
// Hiding all notifications is device-wide setting, managed profiles can only set
// whether their notifications are show in full or redacted.
final boolean showNotifications = managedProfile || Settings.Secure.getIntForUser(
getContentResolver(), LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, mUserId) != 0;
final boolean showUnredacted = Settings.Secure.getIntForUser(
- getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1, mUserId) != 0;
+ getContentResolver(), LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ showUnRedactedDefault ? 1 : 0, mUserId) != 0;
int checkedButtonId = R.id.hide_all;
if (showNotifications) {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettingsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettingsTest.java
index 270a625..dc9cac4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettingsTest.java
@@ -1,5 +1,6 @@
package com.android.settings.fuelgauge.batterysaver;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -82,6 +83,12 @@
verifySchedule("key_battery_saver_percentage", expectedPercentage);
}
+ @Test
+ public void getMetricsCategory_returnExpectedResult() {
+ assertThat(mBatterySaverScheduleSettings.getMetricsCategory())
+ .isEqualTo(SettingsEnums.FUELGAUGE_BATTERY_SAVER_SCHEDULE);
+ }
+
private void setSchedule(int scheduleType, int schedulePercentage) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AUTOMATIC_POWER_SAVE_MODE, scheduleType);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
index db1159e..c5d66a6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
@@ -244,20 +244,4 @@
assertThat(shadowDialog.getMessage()).isEqualTo(
mContext.getText(R.string.battery_tip_dialog_summary_message));
}
-
- @Test
- public void testOnCreateDialog_defenderTip_fireDialog() {
- mDialogFragment = BatteryTipDialogFragment.newInstance(mDefenderTip, METRICS_KEY);
-
- FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
- 0 /* containerViewId */, null /* bundle */);
-
- final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
-
- assertThat(shadowDialog.getTitle()).isEqualTo(
- mContext.getString(R.string.battery_tip_limited_temporarily_title));
- assertThat(shadowDialog.getMessage()).isEqualTo(
- mContext.getString(R.string.battery_tip_limited_temporarily_dialog_msg, "80%"));
- }
}
diff --git a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
index 5c6da49..9d475b8 100644
--- a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
@@ -21,6 +21,7 @@
import com.android.settings.R;
import com.android.settings.RestrictedRadioButton;
import com.android.settings.notification.RedactionInterstitial.RedactionInterstitialFragment;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -38,6 +39,7 @@
@Config(shadows = {
ShadowUtils.class,
ShadowRestrictedLockUtilsInternal.class,
+ SettingsShadowResources.class,
})
public class RedactionInterstitialTest {
private RedactionInterstitial mActivity;
@@ -134,6 +136,28 @@
assertSelectedButton(R.id.redact_sensitive);
}
+ @Test
+ public void defaultShowSensitiveContent_configDeny() {
+ final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
+ Settings.Secure.putIntForUser(resolver,
+ LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, UserHandle.myUserId());
+ setupConfig(false);
+ setupActivity();
+
+ assertSelectedButton(R.id.redact_sensitive);
+ }
+
+ @Test
+ public void defaultShowSensitiveContent_configAllow() {
+ final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
+ Settings.Secure.putIntForUser(resolver,
+ LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, UserHandle.myUserId());
+ setupConfig(true);
+ setupActivity();
+
+ assertSelectedButton(R.id.show_all);
+ }
+
private void setupActivity() {
mActivity = buildActivity(RedactionInterstitial.class, new Intent()).setup().get();
mFragment = (RedactionInterstitialFragment)
@@ -142,6 +166,11 @@
assertThat(mFragment).isNotNull();
}
+ private void setupConfig(boolean allowSensitiveContent) {
+ SettingsShadowResources.overrideResource(
+ R.bool.default_allow_sensitive_lockscreen_content, allowSensitiveContent);
+ }
+
private void setupSettings(int show, int showUnredacted) {
final ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
Settings.Secure.putIntForUser(resolver,
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
index 9846e3f..bd73d8b 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppAllServicesPreferenceTest.kt
@@ -30,6 +30,7 @@
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -38,6 +39,8 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settingslib.spa.testutils.delay
+import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import com.google.common.truth.Truth.assertThat
@@ -140,7 +143,7 @@
setContent()
- composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
@@ -149,6 +152,7 @@
setContent()
composeTestRule.onRoot().performClick()
+ composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
index 60c4f79..39524df 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppLocalePreferenceTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -36,6 +37,8 @@
import com.android.settings.applications.AppLocaleUtil
import com.android.settings.applications.appinfo.AppLocaleDetails
import com.android.settings.localepicker.AppLocalePickerActivity
+import com.android.settingslib.spa.testutils.delay
+import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -103,15 +106,16 @@
composeTestRule.onNodeWithText(context.getString(R.string.app_locale_preference_title))
.assertIsDisplayed()
- composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
- fun whenCanDisplayLocalUi_click_startsActivity() {
+ fun whenCanDisplayLocalUi_click_startActivity() {
doNothing().`when`(context).startActivityAsUser(any(), any())
setContent()
composeTestRule.onRoot().performClick()
+ composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
index a1fb367..35811e2 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppSettingsPreferenceTest.kt
@@ -36,6 +36,7 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
+import com.android.settingslib.spa.testutils.delay
import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import com.google.common.truth.Truth.assertThat
@@ -129,6 +130,7 @@
setContent()
composeTestRule.onRoot().performClick()
+ composeTestRule.delay()
val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
verify(context).startActivityAsUser(intentCaptor.capture(), eq(APP.userHandle))
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreferenceTest.kt
index aeccb07..f4489c6 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/InteractAcrossProfilesDetailsPreferenceTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
@@ -34,6 +35,8 @@
import com.android.settings.R
import com.android.settings.applications.appinfo.AppInfoDashboardFragment
import com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesDetails
+import com.android.settingslib.spa.testutils.delay
+import com.android.settingslib.spa.testutils.waitUntilExists
import com.android.settingslib.spaprivileged.framework.common.crossProfileApps
import org.junit.After
import org.junit.Before
@@ -110,7 +113,7 @@
setContent()
- composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText(SUMMARY))
}
@Test
@@ -119,6 +122,7 @@
setContent()
composeTestRule.onRoot().performClick()
+ composeTestRule.delay()
ExtendedMockito.verify {
AppInfoDashboardFragment.startAppInfoFragment(
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
new file mode 100644
index 0000000..1fac8b5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/model/CredentialModelTest.java
@@ -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);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
index 7a13875..a11650e 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModelTest.java
@@ -24,12 +24,22 @@
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 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 @@
@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 @@
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 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 @@
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 @@
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 @@
@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 @@
.setGatekeeperHAT(hat)
.build();
}
+
+ private VerifyCredentialResponse newBadCredential(int timeout) {
+ if (timeout > 0) {
+ return VerifyCredentialResponse.fromTimeout(timeout);
+ } else {
+ return VerifyCredentialResponse.fromError();
+ }
+ }
}
diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
index 5069ea1..921f182 100644
--- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
+++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModelTest.java
@@ -46,6 +46,7 @@
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;
@@ -93,6 +94,18 @@
}
@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);