Fingerprint Introduction FragmentActivity
Introducing MVVM architecture & fragments to biometric settings. Here, we modify the first page of FingerprintEnrollIntroduction to use new MVVM with Fragment architecture. And with this new architecture, unit test and screen order will be easier to be written or changed. Bug: 236072782 Test: atest FingerprintEnrollmentViewModelTest AutoCredentialViewModelTest FingerprintEnrollIntroViewModelTest FingerprintRepositoryTest Change-Id: Icf12c91625db86c2c99081a0108203e607e77f74
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.data.repository;
|
||||
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_HOME_BUTTON;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UNKNOWN;
|
||||
|
||||
import static com.android.settings.biometrics2.util.FingerprintManagerUtil.setupFingerprintEnrolledFingerprints;
|
||||
import static com.android.settings.biometrics2.util.FingerprintManagerUtil.setupFingerprintFirstSensor;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.testutils.ResourcesUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FingerprintRepositoryTest {
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock private Resources mResources;
|
||||
@Mock private FingerprintManager mFingerprintManager;
|
||||
|
||||
private Context mContext;
|
||||
private FingerprintRepository mFingerprintRepository;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
mFingerprintRepository = new FingerprintRepository(mFingerprintManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanAssumeSensorType() {
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UNKNOWN, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isFalse();
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_REAR, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isFalse();
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isTrue();
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UDFPS_OPTICAL, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isTrue();
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_POWER_BUTTON, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isFalse();
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_HOME_BUTTON, 1);
|
||||
assertThat(mFingerprintRepository.canAssumeUdfps()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxFingerprints() {
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UNKNOWN, 44);
|
||||
assertThat(mFingerprintRepository.getMaxFingerprints()).isEqualTo(44);
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UNKNOWN, 999);
|
||||
assertThat(mFingerprintRepository.getMaxFingerprints()).isEqualTo(999);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNumOfEnrolledFingerprintsSize() {
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, 10, 3);
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, 22, 99);
|
||||
|
||||
assertThat(mFingerprintRepository.getNumOfEnrolledFingerprintsSize(10)).isEqualTo(3);
|
||||
assertThat(mFingerprintRepository.getNumOfEnrolledFingerprintsSize(22)).isEqualTo(99);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxFingerprintsInSuw() {
|
||||
setupSuwMaxFingerprintsEnrollable(mContext, mResources, 333);
|
||||
assertThat(mFingerprintRepository.getMaxFingerprintsInSuw(mResources))
|
||||
.isEqualTo(333);
|
||||
|
||||
setupSuwMaxFingerprintsEnrollable(mContext, mResources, 20);
|
||||
assertThat(mFingerprintRepository.getMaxFingerprintsInSuw(mResources)).isEqualTo(20);
|
||||
}
|
||||
|
||||
public static void setupSuwMaxFingerprintsEnrollable(
|
||||
@NonNull Context context,
|
||||
@NonNull Resources mockedResources,
|
||||
int numOfFp) {
|
||||
final int resId = ResourcesUtils.getResourcesId(context, "integer",
|
||||
"suw_max_fingerprints_enrollable");
|
||||
when(mockedResources.getInteger(resId)).thenReturn(numOfFp);
|
||||
}
|
||||
}
|
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* 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.viewmodel;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
|
||||
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_CHALLENGE;
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_SENSOR_ID;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_SENSOR_ID;
|
||||
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.ChallengeGenerator;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CredentialAction;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.GenerateChallengeCallback;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.SystemClock;
|
||||
import android.os.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;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.settings.biometrics2.ui.model.CredentialModel;
|
||||
import com.android.settings.password.ChooseLockPattern;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.testutils.InstantTaskExecutorRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AutoCredentialViewModelTest {
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||
|
||||
@Mock private LifecycleOwner mLifecycleOwner;
|
||||
@Mock private LockPatternUtils mLockPatternUtils;
|
||||
private TestChallengeGenerator mChallengeGenerator = null;
|
||||
private AutoCredentialViewModel mAutoCredentialViewModel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mChallengeGenerator = new TestChallengeGenerator();
|
||||
mAutoCredentialViewModel = new AutoCredentialViewModel(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mLockPatternUtils,
|
||||
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) {
|
||||
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() {
|
||||
final int userId = 99;
|
||||
mAutoCredentialViewModel.setCredentialModel(newValidTokenCredentialModel(userId));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
verifyNothingHappen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_needToChooseLock() {
|
||||
final int userId = 100;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_UNSPECIFIED);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_needToConfirmLockFoSomething() {
|
||||
final int userId = 101;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_needToConfirmLockForNumeric() {
|
||||
final int userId = 102;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_NUMERIC);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_needToConfirmLockForAlphabetic() {
|
||||
final int userId = 103;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_ALPHABETIC);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
verifyOnlyActionLiveData(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkCredential_generateChallenge() {
|
||||
final int userId = 104;
|
||||
final long gkPwHandle = 1111L;
|
||||
final CredentialModel credentialModel = newGkPwHandleCredentialModel(userId, gkPwHandle);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final int newSensorId = 10;
|
||||
final long newChallenge = 20L;
|
||||
setupGenerateTokenFlow(gkPwHandle, userId, newSensorId, newChallenge);
|
||||
|
||||
// Run credential check
|
||||
mAutoCredentialViewModel.onCreate(mLifecycleOwner);
|
||||
|
||||
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(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserId() {
|
||||
final int userId = 106;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
|
||||
// Get userId
|
||||
assertThat(mAutoCredentialViewModel.getUserId()).isEqualTo(userId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_invalidChooseLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_invalidConfirmLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataChooseLock() {
|
||||
final int userId = 108;
|
||||
final long gkPwHandle = 4444L;
|
||||
mAutoCredentialViewModel.setCredentialModel(
|
||||
newGkPwHandleCredentialModel(userId, gkPwHandle));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataConfirmLock() {
|
||||
final int userId = 109;
|
||||
mAutoCredentialViewModel.setCredentialModel(newInvalidChallengeCredentialModel(userId));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mAutoCredentialViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
verifyNothingHappen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validChooseLock() {
|
||||
final int userId = 108;
|
||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
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);
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
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(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validConfirmLock() {
|
||||
final int userId = 109;
|
||||
final CredentialModel credentialModel = newInvalidChallengeCredentialModel(userId);
|
||||
mAutoCredentialViewModel.setCredentialModel(credentialModel);
|
||||
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);
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
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(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
}
|
||||
|
||||
public static class TestChallengeGenerator implements ChallengeGenerator {
|
||||
public int mSensorId = INVALID_SENSOR_ID;
|
||||
public int mUserId = UserHandle.myUserId();
|
||||
public long mChallenge = INVALID_CHALLENGE;
|
||||
public int mCallbackRunCount = 0;
|
||||
private GenerateChallengeCallback mCallback;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public GenerateChallengeCallback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(@Nullable GenerateChallengeCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChallenge(int userId) {
|
||||
final GenerateChallengeCallback callback = mCallback;
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
callback.onChallengeGenerated(mSensorId, mUserId, mChallenge);
|
||||
++mCallbackRunCount;
|
||||
}
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse newGoodCredential(long gkPwHandle, @NonNull byte[] hat) {
|
||||
return new VerifyCredentialResponse.Builder()
|
||||
.setGatekeeperPasswordHandle(gkPwHandle)
|
||||
.setGatekeeperHAT(hat)
|
||||
.build();
|
||||
}
|
||||
}
|
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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.viewmodel;
|
||||
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
|
||||
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC;
|
||||
|
||||
import static com.android.settings.biometrics2.data.repository.FingerprintRepositoryTest.setupSuwMaxFingerprintsEnrollable;
|
||||
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX;
|
||||
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_OK;
|
||||
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus.FINGERPRINT_ENROLLABLE_UNKNOWN;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newAllFalseRequest;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newIsSuwDeferredRequest;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newIsSuwPortalRequest;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newIsSuwRequest;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newIsSuwSuggestedActionFlowRequest;
|
||||
import static com.android.settings.biometrics2.util.FingerprintManagerUtil.setupFingerprintEnrolledFingerprints;
|
||||
import static com.android.settings.biometrics2.util.FingerprintManagerUtil.setupFingerprintFirstSensor;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
||||
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
|
||||
import com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus;
|
||||
import com.android.settings.testutils.InstantTaskExecutorRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FingerprintEnrollIntroViewModelTest {
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||
|
||||
@Mock private Resources mResources;
|
||||
@Mock private LifecycleOwner mLifecycleOwner;
|
||||
@Mock private FingerprintManager mFingerprintManager;
|
||||
|
||||
private Application mApplication;
|
||||
private FingerprintRepository mFingerprintRepository;
|
||||
private FingerprintEnrollIntroViewModel mViewModel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mApplication = ApplicationProvider.getApplicationContext();
|
||||
mFingerprintRepository = new FingerprintRepository(mFingerprintManager);
|
||||
mViewModel = new FingerprintEnrollIntroViewModel(mApplication, mFingerprintRepository);
|
||||
// MediatorLiveData won't update itself unless observed
|
||||
mViewModel.getPageStatusLiveData().observeForever(event -> {});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPageStatusLiveDataDefaultValue() {
|
||||
final FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.hasScrollToBottom()).isFalse();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetEnrollmentRequest() {
|
||||
final EnrollmentRequest request = newAllFalseRequest(mApplication);
|
||||
|
||||
mViewModel.setEnrollmentRequest(request);
|
||||
|
||||
assertThat(mViewModel.getEnrollmentRequest()).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartToUpdateEnrollableStatus_isSuw() {
|
||||
final int userId = 44;
|
||||
mViewModel.setUserId(userId);
|
||||
mViewModel.setEnrollmentRequest(newIsSuwRequest(mApplication));
|
||||
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 0);
|
||||
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
|
||||
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 1);
|
||||
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartToUpdateEnrollableStatus_isNotSuw() {
|
||||
testOnStartToUpdateEnrollableStatus(newAllFalseRequest(mApplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartToUpdateEnrollableStatus_isSuwDeferred() {
|
||||
testOnStartToUpdateEnrollableStatus(newIsSuwDeferredRequest(mApplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartToUpdateEnrollableStatus_isSuwPortal() {
|
||||
testOnStartToUpdateEnrollableStatus(newIsSuwPortalRequest(mApplication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStartToUpdateEnrollableStatus_isSuwSuggestedActionFlow() {
|
||||
testOnStartToUpdateEnrollableStatus(newIsSuwSuggestedActionFlowRequest(mApplication));
|
||||
}
|
||||
|
||||
private void testOnStartToUpdateEnrollableStatus(@NonNull EnrollmentRequest request) {
|
||||
final int userId = 45;
|
||||
mViewModel.setUserId(userId);
|
||||
mViewModel.setEnrollmentRequest(request);
|
||||
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 0);
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
|
||||
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 5);
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textCanAssumeUdfps() {
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_UDFPS_ULTRASONIC, 1);
|
||||
assertThat(mViewModel.canAssumeUdfps()).isEqualTo(true);
|
||||
|
||||
setupFingerprintFirstSensor(mFingerprintManager, TYPE_REAR, 1);
|
||||
assertThat(mViewModel.canAssumeUdfps()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsParentalConsentRequired() {
|
||||
// We shall not mock FingerprintRepository, but
|
||||
// FingerprintRepository.isParentalConsentRequired() calls static method inside, we can't
|
||||
// mock static method
|
||||
final FingerprintRepository fingerprintRepository = mock(FingerprintRepository.class);
|
||||
mViewModel = new FingerprintEnrollIntroViewModel(mApplication, fingerprintRepository);
|
||||
|
||||
when(fingerprintRepository.isParentalConsentRequired(mApplication)).thenReturn(true);
|
||||
assertThat(mViewModel.isParentalConsentRequired()).isEqualTo(true);
|
||||
|
||||
when(fingerprintRepository.isParentalConsentRequired(mApplication)).thenReturn(false);
|
||||
assertThat(mViewModel.isParentalConsentRequired()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsBiometricUnlockDisabledByAdmin() {
|
||||
// We shall not mock FingerprintRepository, but
|
||||
// FingerprintRepository.isDisabledByAdmin() calls static method inside, we can't mock
|
||||
// static method
|
||||
final FingerprintRepository fingerprintRepository = mock(FingerprintRepository.class);
|
||||
mViewModel = new FingerprintEnrollIntroViewModel(mApplication, fingerprintRepository);
|
||||
|
||||
final int userId = 33;
|
||||
mViewModel.setUserId(userId);
|
||||
|
||||
when(fingerprintRepository.isDisabledByAdmin(mApplication, userId)).thenReturn(true);
|
||||
assertThat(mViewModel.isBiometricUnlockDisabledByAdmin()).isEqualTo(true);
|
||||
|
||||
when(fingerprintRepository.isDisabledByAdmin(mApplication, userId)).thenReturn(false);
|
||||
assertThat(mViewModel.isBiometricUnlockDisabledByAdmin()).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHasScrolledToBottom() {
|
||||
mViewModel.setHasScrolledToBottom();
|
||||
|
||||
FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
|
||||
assertThat(status.hasScrollToBottom()).isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnNextButtonClick_enrollNext() {
|
||||
final int userId = 46;
|
||||
mViewModel.setUserId(userId);
|
||||
mViewModel.setEnrollmentRequest(newIsSuwRequest(mApplication));
|
||||
|
||||
// Set latest status to FINGERPRINT_ENROLLABLE_OK
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 0);
|
||||
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
|
||||
|
||||
// Perform click on `next`
|
||||
mViewModel.onNextButtonClick(null);
|
||||
|
||||
assertThat(mViewModel.getActionLiveData().getValue())
|
||||
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnNextButtonClick_doneAndFinish() {
|
||||
final int userId = 46;
|
||||
mViewModel.setUserId(userId);
|
||||
mViewModel.setEnrollmentRequest(newIsSuwRequest(mApplication));
|
||||
|
||||
// Set latest status to FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, 1);
|
||||
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
|
||||
mViewModel.onStart(mLifecycleOwner);
|
||||
FingerprintEnrollIntroStatus status = mViewModel.getPageStatusLiveData().getValue();
|
||||
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
|
||||
|
||||
// Perform click on `next`
|
||||
mViewModel.onNextButtonClick(null);
|
||||
|
||||
assertThat(mViewModel.getActionLiveData().getValue())
|
||||
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnSkipOrCancelButtonClick() {
|
||||
mViewModel.onSkipOrCancelButtonClick(null);
|
||||
|
||||
assertThat(mViewModel.getActionLiveData().getValue())
|
||||
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL);
|
||||
}
|
||||
}
|
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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.viewmodel;
|
||||
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED;
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_SKIP;
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT;
|
||||
import static com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction.EXTRA_FINGERPRINT_ENROLLED_COUNT;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel.SAVED_STATE_IS_WAITING_ACTIVITY_RESULT;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newAllFalseRequest;
|
||||
import static com.android.settings.biometrics2.util.EnrollmentRequestUtil.newIsSuwRequest;
|
||||
import static com.android.settings.biometrics2.util.FingerprintManagerUtil.setupFingerprintEnrolledFingerprints;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Intent;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
|
||||
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
|
||||
import com.android.settings.password.SetupSkipDialog;
|
||||
import com.android.settings.testutils.InstantTaskExecutorRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FingerprintEnrollmentViewModelTest {
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||
|
||||
@Mock private FingerprintManager mFingerprintManager;
|
||||
@Mock private KeyguardManager mKeyguardManager;
|
||||
|
||||
private Application mApplication;
|
||||
private FingerprintRepository mFingerprintRepository;
|
||||
private FingerprintEnrollmentViewModel mViewModel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mApplication = ApplicationProvider.getApplicationContext();
|
||||
mFingerprintRepository = new FingerprintRepository(mFingerprintManager);
|
||||
mViewModel = new FingerprintEnrollmentViewModel(mApplication, mFingerprintRepository,
|
||||
mKeyguardManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRequest() {
|
||||
when(mKeyguardManager.isKeyguardSecure()).thenReturn(true);
|
||||
assertThat(mViewModel.getRequest()).isNull();
|
||||
|
||||
final EnrollmentRequest request = newAllFalseRequest(mApplication);
|
||||
mViewModel.setRequest(request);
|
||||
assertThat(mViewModel.getRequest()).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNextActivityBaseIntentExtras() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
assertThat(mViewModel.getNextActivityBaseIntentExtras()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelaySkip1Result() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final ActivityResult result = new ActivityResult(RESULT_SKIP, null);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
|
||||
assertThat(mViewModel.getSetResultLiveData().getValue()).isEqualTo(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelaySkip2Result() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final ActivityResult result = new ActivityResult(SetupSkipDialog.RESULT_SKIP, null);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
|
||||
assertThat(mViewModel.getSetResultLiveData().getValue()).isEqualTo(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayNullDataTimeoutResult() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final ActivityResult result = new ActivityResult(RESULT_TIMEOUT, null);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isEqualTo(result.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayWithDataTimeoutResult() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final Intent intent = new Intent("testAction");
|
||||
intent.putExtra("testKey", "testValue");
|
||||
final ActivityResult result = new ActivityResult(RESULT_TIMEOUT, intent);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isEqualTo(intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayNullDataFinishResult() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final ActivityResult result = new ActivityResult(RESULT_FINISHED, null);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isEqualTo(result.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayWithDataFinishResult() {
|
||||
mViewModel.setRequest(newAllFalseRequest(mApplication));
|
||||
final Intent intent = new Intent("testAction");
|
||||
intent.putExtra("testKey", "testValue");
|
||||
final ActivityResult result = new ActivityResult(RESULT_FINISHED, intent);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, 100);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isEqualTo(intent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayNullDataFinishResultAsNewData() {
|
||||
when(mKeyguardManager.isKeyguardSecure()).thenReturn(true);
|
||||
final int userId = 111;
|
||||
final int numOfFp = 4;
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, numOfFp);
|
||||
mViewModel.setRequest(newIsSuwRequest(mApplication));
|
||||
final ActivityResult result = new ActivityResult(RESULT_FINISHED, null);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, userId);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isNotNull();
|
||||
assertThat(setResult.getData().getExtras()).isNotNull();
|
||||
assertThat(setResult.getData().getExtras().getInt(EXTRA_FINGERPRINT_ENROLLED_COUNT, -1))
|
||||
.isEqualTo(numOfFp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnContinueEnrollActivityResult_shouldRelayWithDataFinishResultAsNewData() {
|
||||
when(mKeyguardManager.isKeyguardSecure()).thenReturn(true);
|
||||
final int userId = 20;
|
||||
final int numOfFp = 9;
|
||||
setupFingerprintEnrolledFingerprints(mFingerprintManager, userId, numOfFp);
|
||||
mViewModel.setRequest(newIsSuwRequest(mApplication));
|
||||
final String action = "testAction";
|
||||
final String key = "testKey";
|
||||
final String value = "testValue";
|
||||
final Intent intent = new Intent(action);
|
||||
intent.putExtra(key, value);
|
||||
final ActivityResult result = new ActivityResult(RESULT_FINISHED, intent);
|
||||
|
||||
// Run onContinueEnrollActivityResult
|
||||
mViewModel.onContinueEnrollActivityResult(result, userId);
|
||||
final ActivityResult setResult = mViewModel.getSetResultLiveData().getValue();
|
||||
|
||||
assertThat(setResult).isNotNull();
|
||||
assertThat(setResult.getResultCode()).isEqualTo(result.getResultCode());
|
||||
assertThat(setResult.getData()).isNotNull();
|
||||
assertThat(setResult.getData().getExtras()).isNotNull();
|
||||
assertThat(setResult.getData().getExtras().getInt(EXTRA_FINGERPRINT_ENROLLED_COUNT, -1))
|
||||
.isEqualTo(numOfFp);
|
||||
assertThat(setResult.getData().getExtras().getString(key)).isEqualTo(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSavedInstanceState() {
|
||||
final Bundle bundle = new Bundle();
|
||||
mViewModel.isWaitingActivityResult().set(true);
|
||||
|
||||
// setSavedInstanceState() as false
|
||||
bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, false);
|
||||
mViewModel.setSavedInstanceState(bundle);
|
||||
assertThat(mViewModel.isWaitingActivityResult().get()).isFalse();
|
||||
|
||||
// setSavedInstanceState() as false
|
||||
bundle.putBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT, true);
|
||||
mViewModel.setSavedInstanceState(bundle);
|
||||
assertThat(mViewModel.isWaitingActivityResult().get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnSaveInstanceState() {
|
||||
final Bundle bundle = new Bundle();
|
||||
|
||||
// setSavedInstanceState() as false
|
||||
mViewModel.isWaitingActivityResult().set(false);
|
||||
mViewModel.onSaveInstanceState(bundle);
|
||||
assertThat(bundle.getBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT)).isFalse();
|
||||
|
||||
// setSavedInstanceState() as false
|
||||
mViewModel.isWaitingActivityResult().set(true);
|
||||
mViewModel.onSaveInstanceState(bundle);
|
||||
assertThat(bundle.getBoolean(SAVED_STATE_IS_WAITING_ACTIVITY_RESULT)).isTrue();
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
|
||||
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP;
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_FIRST_RUN;
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_PORTAL_SETUP;
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW;
|
||||
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_THEME;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
|
||||
|
||||
public class EnrollmentRequestUtil {
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newAllFalseRequest(@NonNull Context context) {
|
||||
return newRequest(context, false, false, false, false, false, false, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newIsSuwRequest(@NonNull Context context) {
|
||||
return newRequest(context, true, false, false, false, false, false, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newIsSuwDeferredRequest(@NonNull Context context) {
|
||||
return newRequest(context, true, true, false, false, false, false, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newIsSuwPortalRequest(@NonNull Context context) {
|
||||
return newRequest(context, true, false, true, false, false, false, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newIsSuwSuggestedActionFlowRequest(
|
||||
@NonNull Context context) {
|
||||
return newRequest(context, true, false, false, true, false, false, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static EnrollmentRequest newRequest(@NonNull Context context, boolean isSuw,
|
||||
boolean isSuwDeferred, boolean isSuwPortal, boolean isSuwSuggestedActionFlow,
|
||||
boolean isSuwFirstRun, boolean isFromSettingsSummery, String theme) {
|
||||
Intent i = new Intent();
|
||||
i.putExtra(EXTRA_IS_SETUP_FLOW, isSuw);
|
||||
i.putExtra(EXTRA_IS_DEFERRED_SETUP, isSuwDeferred);
|
||||
i.putExtra(EXTRA_IS_PORTAL_SETUP, isSuwPortal);
|
||||
i.putExtra(EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW, isSuwSuggestedActionFlow);
|
||||
i.putExtra(EXTRA_IS_FIRST_RUN, isSuwFirstRun);
|
||||
i.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, isFromSettingsSummery);
|
||||
if (!TextUtils.isEmpty(theme)) {
|
||||
i.putExtra(EXTRA_THEME, theme);
|
||||
}
|
||||
return new EnrollmentRequest(i, context);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorProperties;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class FingerprintManagerUtil {
|
||||
|
||||
public static void setupFingerprintFirstSensor(
|
||||
@NonNull FingerprintManager mockedFingerprintManager,
|
||||
@FingerprintSensorProperties.SensorType int sensorType,
|
||||
int maxEnrollmentsPerUser) {
|
||||
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
|
||||
props.add(new FingerprintSensorPropertiesInternal(
|
||||
0 /* sensorId */,
|
||||
SensorProperties.STRENGTH_STRONG,
|
||||
maxEnrollmentsPerUser,
|
||||
new ArrayList<>() /* componentInfo */,
|
||||
sensorType,
|
||||
true /* resetLockoutRequiresHardwareAuthToken */));
|
||||
when(mockedFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
|
||||
}
|
||||
|
||||
public static void setupFingerprintEnrolledFingerprints(
|
||||
@NonNull FingerprintManager mockedFingerprintManager,
|
||||
int userId,
|
||||
int enrolledFingerprints) {
|
||||
final ArrayList<Fingerprint> ret = new ArrayList<>();
|
||||
for (int i = 0; i < enrolledFingerprints; ++i) {
|
||||
ret.add(new Fingerprint("name", 0, 0, 0L));
|
||||
}
|
||||
when(mockedFingerprintManager.getEnrolledFingerprints(userId)).thenReturn(ret);
|
||||
}
|
||||
}
|
@@ -25,6 +25,7 @@ import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
@@ -73,6 +74,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
public final AwareFeatureProvider mAwareFeatureProvider;
|
||||
public final FaceFeatureProvider mFaceFeatureProvider;
|
||||
public final BiometricsRepositoryProvider mBiometricsRepositoryProvider;
|
||||
|
||||
public PanelFeatureProvider panelFeatureProvider;
|
||||
public SlicesFeatureProvider slicesFeatureProvider;
|
||||
@@ -120,6 +122,7 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
|
||||
mAwareFeatureProvider = mock(AwareFeatureProvider.class);
|
||||
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
|
||||
mBiometricsRepositoryProvider = mock(BiometricsRepositoryProvider.class);
|
||||
wifiTrackerLibProvider = mock(WifiTrackerLibProvider.class);
|
||||
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
|
||||
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
|
||||
@@ -242,6 +245,11 @@ public class FakeFeatureFactory extends FeatureFactory {
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiometricsRepositoryProvider getBiometricsRepositoryProvider() {
|
||||
return mBiometricsRepositoryProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WifiTrackerLibProvider getWifiTrackerLibProvider() {
|
||||
return wifiTrackerLibProvider;
|
||||
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.testutils;
|
||||
|
||||
import androidx.arch.core.executor.ArchTaskExecutor;
|
||||
import androidx.arch.core.executor.TaskExecutor;
|
||||
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
/**
|
||||
* A JUnit Test Rule that swaps the background executor used by the Architecture Components with a
|
||||
* different one which executes each task synchronously.
|
||||
*
|
||||
* We can't refer it in prebuilt androidX library.
|
||||
* Copied it from androidx/arch/core/executor/testing/InstantTaskExecutorRule.java
|
||||
*/
|
||||
public class InstantTaskExecutorRule extends TestWatcher {
|
||||
@Override
|
||||
protected void starting(Description description) {
|
||||
super.starting(description);
|
||||
ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
|
||||
@Override
|
||||
public void executeOnDiskIO(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postToMainThread(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMainThread() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finished(Description description) {
|
||||
super.finished(description);
|
||||
ArchTaskExecutor.getInstance().setDelegate(null);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user