Merge "Fingerprint Introduction FragmentActivity"
This commit is contained in:
committed by
Android (Google) Code Review
commit
148774d287
@@ -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