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:
Milton Wu
2022-09-14 14:26:05 +08:00
parent 45be6bae05
commit b9b8b8a512
30 changed files with 3319 additions and 1 deletions

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}
}