[BiometricsV2] Refactor AutoCredentialViewModel
Refactor AutoCredentialViewModelTest and FingerprintEnrollmentViewModel to kotlin and change LiveData to Flow Bug: 286197659 Test: atest -m CredentialModelTest Test: atest -m AutoCredentialViewModelTest Test: atest -m FingerprintEnrollmentViewModelTest Test: atest -m FingerprintEnrollmentActivityTest Test: atest -m biometrics-enrollment-test Change-Id: I84bab0b46e023303c0046a6ae6886ab1cf9458b8
This commit is contained in:
@@ -38,22 +38,6 @@ class CredentialModelTest {
|
||||
Truth.assertThat(credentialModel.userId).isEqualTo(UserHandle.myUserId())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSameValueFromBundle() {
|
||||
val bundle = newCredentialModelIntentExtras(1234, 6677L, byteArrayOf(33, 44, 55), 987654321)
|
||||
val model1 = CredentialModel(bundle, clock)
|
||||
val model2 = CredentialModel(model1.bundle, clock)
|
||||
verifySameCredentialModels(model1, model2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSameValueFromBundle_nullToken() {
|
||||
val bundle = newCredentialModelIntentExtras(22, 33L, null, 21L)
|
||||
val model1 = CredentialModel(bundle, clock)
|
||||
val model2 = CredentialModel(model1.bundle, clock)
|
||||
verifySameCredentialModels(model1, model2)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun newCredentialModelIntentExtras(
|
||||
@@ -148,36 +132,5 @@ class CredentialModelTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun verifySameCredentialModels(
|
||||
model1: CredentialModel,
|
||||
model2: CredentialModel
|
||||
) {
|
||||
Truth.assertThat(model1.userId).isEqualTo(model2.userId)
|
||||
Truth.assertThat(model1.challenge).isEqualTo(model2.challenge)
|
||||
Truth.assertThat(model1.gkPwHandle).isEqualTo(model2.gkPwHandle)
|
||||
val token1 = model1.token
|
||||
val token2 = model2.token
|
||||
if (token1 == null) {
|
||||
Truth.assertThat(token2).isNull()
|
||||
} else {
|
||||
Truth.assertThat(token2).isNotNull()
|
||||
Truth.assertThat(token1.size).isEqualTo(token2!!.size)
|
||||
for (i in token1.indices) {
|
||||
Truth.assertThat(token1[i]).isEqualTo(
|
||||
token2[i]
|
||||
)
|
||||
}
|
||||
}
|
||||
val bundle1 = model1.bundle
|
||||
val bundle2 = model2.bundle
|
||||
val keySet1 = bundle1.keySet()
|
||||
Truth.assertThat(keySet1 == bundle2.keySet()).isTrue()
|
||||
checkBundleIntValue(bundle1, bundle2, Intent.EXTRA_USER_ID)
|
||||
checkBundleIntValue(bundle1, bundle2, BiometricEnrollBase.EXTRA_KEY_SENSOR_ID)
|
||||
checkBundleLongValue(bundle1, bundle2, BiometricEnrollBase.EXTRA_KEY_CHALLENGE)
|
||||
checkBundleByteArrayValue(bundle1, bundle2, BiometricEnrollBase.EXTRA_KEY_CHALLENGE)
|
||||
checkBundleLongValue(bundle1, bundle2, ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,596 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.biometrics2.ui.model.CredentialModel.INVALID_CHALLENGE;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModel.INVALID_GK_PW_HANDLE;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newCredentialModelIntentExtras;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newGkPwHandleCredentialIntentExtras;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newOnlySensorValidCredentialIntentExtras;
|
||||
import static com.android.settings.biometrics2.ui.model.CredentialModelTest.newValidTokenCredentialIntentExtras;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.ChallengeGenerator;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CredentialAction;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.GenerateChallengeCallback;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.KEY_CREDENTIAL_MODEL;
|
||||
import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.annotation.Nullable;
|
||||
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.password.ChooseLockPattern;
|
||||
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;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AutoCredentialViewModelTest {
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
|
||||
|
||||
@Mock private LockPatternUtils mLockPatternUtils;
|
||||
private TestChallengeGenerator mChallengeGenerator = null;
|
||||
private AutoCredentialViewModel mViewModel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mChallengeGenerator = new TestChallengeGenerator();
|
||||
mViewModel = new AutoCredentialViewModel(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mLockPatternUtils,
|
||||
mChallengeGenerator);
|
||||
}
|
||||
|
||||
private void setupGenerateChallenge(int userId, int newSensorId, long newChallenge) {
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
mChallengeGenerator.mUserId = userId;
|
||||
mChallengeGenerator.mSensorId = newSensorId;
|
||||
mChallengeGenerator.mChallenge = newChallenge;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent() {
|
||||
final Bundle extras = newCredentialModelIntentExtras(12, 33, new byte[] { 2, 3 }, 3L);
|
||||
|
||||
AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mLockPatternUtils,
|
||||
mChallengeGenerator);
|
||||
|
||||
mViewModel.setCredentialModel(null, new Intent().putExtras(extras));
|
||||
final Bundle savedInstance = new Bundle();
|
||||
mViewModel.onSaveInstanceState(savedInstance);
|
||||
viewModel2.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
assertThat(mViewModel.getUserId()).isEqualTo(viewModel2.getUserId());
|
||||
final byte[] token1 = mViewModel.getToken();
|
||||
final byte[] token2 = viewModel2.getToken();
|
||||
assertThat(token1).isNotNull();
|
||||
assertThat(token2).isNotNull();
|
||||
assertThat(token1.length).isEqualTo(token2.length);
|
||||
for (int i = 0; i < token2.length; ++i) {
|
||||
assertThat(token1[i]).isEqualTo(token2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCredentialModel_sameResultFromSavedInstanceOrIntent_invalidValues() {
|
||||
final Bundle extras = newCredentialModelIntentExtras(UserHandle.USER_NULL,
|
||||
INVALID_CHALLENGE, null, INVALID_GK_PW_HANDLE);
|
||||
|
||||
AutoCredentialViewModel viewModel2 = new AutoCredentialViewModel(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
mLockPatternUtils,
|
||||
mChallengeGenerator);
|
||||
|
||||
mViewModel.setCredentialModel(null, new Intent().putExtras(extras));
|
||||
final Bundle savedInstance = new Bundle();
|
||||
mViewModel.onSaveInstanceState(savedInstance);
|
||||
viewModel2.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
assertThat(mViewModel.getUserId()).isEqualTo(UserHandle.USER_NULL);
|
||||
assertThat(viewModel2.getUserId()).isEqualTo(UserHandle.USER_NULL);
|
||||
assertThat(mViewModel.getToken()).isNull();
|
||||
assertThat(viewModel2.getToken()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_validCredentialCase() {
|
||||
final int userId = 99;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newValidTokenCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_VALID);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_needToChooseLock() {
|
||||
final int userId = 100;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_UNSPECIFIED);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_needToConfirmLockForSomething() {
|
||||
final int userId = 101;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_needToConfirmLockForNumeric() {
|
||||
final int userId = 102;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_NUMERIC);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_needToConfirmLockForAlphabetic() {
|
||||
final int userId = 103;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_ALPHABETIC);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_generateChallenge() {
|
||||
final int userId = 104;
|
||||
final long gkPwHandle = 1111L;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final int newSensorId = 10;
|
||||
final long newChallenge = 20L;
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
final AtomicBoolean hasCalledRemoveGkPwHandle = new AtomicBoolean();
|
||||
doAnswer(invocation -> {
|
||||
hasCalledRemoveGkPwHandle.set(true);
|
||||
return null;
|
||||
}).when(mLockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle);
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CREDENTIAL_IS_GENERATING_CHALLENGE);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
|
||||
// Check data inside CredentialModel
|
||||
assertThat(mViewModel.getToken()).isNotNull();
|
||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isFalse();
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
final Bundle generatingChallengeExtras = mViewModel.createGeneratingChallengeExtras();
|
||||
assertThat(generatingChallengeExtras).isNotNull();
|
||||
assertThat(generatingChallengeExtras.getLong(EXTRA_KEY_CHALLENGE)).isEqualTo(newChallenge);
|
||||
final byte[] tokens = generatingChallengeExtras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
assertThat(tokens).isNotNull();
|
||||
assertThat(tokens.length).isEqualTo(1);
|
||||
assertThat(tokens[0]).isEqualTo(1);
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckCredential_generateChallengeFail() {
|
||||
final int userId = 104;
|
||||
final long gkPwHandle = 1111L;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final int newSensorId = 10;
|
||||
final long newChallenge = 20L;
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newBadCredential(0));
|
||||
|
||||
// Run credential check
|
||||
@CredentialAction final int action = mViewModel.checkCredential();
|
||||
|
||||
assertThat(action).isEqualTo(CREDENTIAL_IS_GENERATING_CHALLENGE);
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isTrue();
|
||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
|
||||
// Check onSaveInstanceState()
|
||||
final Bundle actualBundle = new Bundle();
|
||||
mViewModel.onSaveInstanceState(actualBundle);
|
||||
assertThat(actualBundle.getBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserId_fromIntent() {
|
||||
final int userId = 106;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
|
||||
// Get userId
|
||||
assertThat(mViewModel.getUserId()).isEqualTo(userId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserId_fromSavedInstance() {
|
||||
final int userId = 106;
|
||||
final Bundle savedInstance = new Bundle();
|
||||
savedInstance.putBundle(KEY_CREDENTIAL_MODEL,
|
||||
newOnlySensorValidCredentialIntentExtras(userId));
|
||||
mViewModel.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
// Get userId
|
||||
assertThat(mViewModel.getUserId()).isEqualTo(userId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateGeneratingChallengeExtras_generateChallenge() {
|
||||
final Bundle credentialExtras = newValidTokenCredentialIntentExtras(200);
|
||||
final Bundle savedInstance = new Bundle();
|
||||
savedInstance.putBundle(KEY_CREDENTIAL_MODEL, credentialExtras);
|
||||
savedInstance.putBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL, true);
|
||||
mViewModel.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
final Bundle actualExtras = mViewModel.createGeneratingChallengeExtras();
|
||||
assertThat(actualExtras).isNotNull();
|
||||
assertThat(actualExtras.getLong(EXTRA_KEY_CHALLENGE))
|
||||
.isEqualTo(credentialExtras.getLong(EXTRA_KEY_CHALLENGE));
|
||||
final byte[] actualToken = actualExtras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
final byte[] expectedToken = credentialExtras.getByteArray(EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
assertThat(actualToken).isNotNull();
|
||||
assertThat(expectedToken).isNotNull();
|
||||
assertThat(actualToken.length).isEqualTo(expectedToken.length);
|
||||
for (int i = 0; i < actualToken.length; ++i) {
|
||||
assertWithMessage("tokens[" + i + "] not match").that(actualToken[i])
|
||||
.isEqualTo(expectedToken[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateGeneratingChallengeExtras_notGenerateChallenge() {
|
||||
final Bundle credentialExtras = newValidTokenCredentialIntentExtras(201);
|
||||
final Bundle savedInstance = new Bundle();
|
||||
savedInstance.putBundle(KEY_CREDENTIAL_MODEL, credentialExtras);
|
||||
savedInstance.putBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL, false);
|
||||
mViewModel.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateGeneratingChallengeExtras_invalidToken() {
|
||||
final Bundle credentialExtras = newOnlySensorValidCredentialIntentExtras(202);
|
||||
final Bundle savedInstance = new Bundle();
|
||||
savedInstance.putBundle(KEY_CREDENTIAL_MODEL, credentialExtras);
|
||||
savedInstance.putBoolean(KEY_IS_GENERATING_CHALLENGE_DURING_CHECKING_CREDENTIAL, true);
|
||||
mViewModel.setCredentialModel(savedInstance, new Intent());
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(mViewModel.createGeneratingChallengeExtras()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_invalidChooseLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_invalidConfirmLock() {
|
||||
final int userId = 107;
|
||||
final long gkPwHandle = 3333L;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK + 1, intent));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataChooseLock() {
|
||||
final int userId = 108;
|
||||
final long gkPwHandle = 4444L;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle)));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_nullDataConfirmLock() {
|
||||
final int userId = 109;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
|
||||
// run checkNewCredentialFromActivityResult()
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK, null));
|
||||
|
||||
assertThat(ret).isFalse();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validChooseLock() {
|
||||
final int userId = 108;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final long gkPwHandle = 6666L;
|
||||
final int newSensorId = 50;
|
||||
final long newChallenge = 60L;
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
final AtomicBoolean hasCalledRemoveGkPwHandle = new AtomicBoolean();
|
||||
doAnswer(invocation -> {
|
||||
hasCalledRemoveGkPwHandle.set(true);
|
||||
return null;
|
||||
}).when(mLockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle);
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
final Intent intent = new Intent().putExtra(EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(true,
|
||||
new ActivityResult(ChooseLockPattern.RESULT_FINISHED, intent));
|
||||
|
||||
assertThat(ret).isTrue();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
assertThat(mViewModel.getToken()).isNotNull();
|
||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckNewCredentialFromActivityResult_validConfirmLock() {
|
||||
final int userId = 109;
|
||||
mViewModel.setCredentialModel(null,
|
||||
new Intent().putExtras(newOnlySensorValidCredentialIntentExtras(userId)));
|
||||
when(mLockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
PASSWORD_QUALITY_SOMETHING);
|
||||
|
||||
final long gkPwHandle = 5555L;
|
||||
final int newSensorId = 80;
|
||||
final long newChallenge = 90L;
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge);
|
||||
when(mLockPatternUtils.verifyGatekeeperPasswordHandle(gkPwHandle, newChallenge, userId))
|
||||
.thenReturn(newGoodCredential(gkPwHandle, new byte[] { 1 }));
|
||||
|
||||
final AtomicBoolean hasCalledRemoveGkPwHandle = new AtomicBoolean();
|
||||
doAnswer(invocation -> {
|
||||
hasCalledRemoveGkPwHandle.set(true);
|
||||
return null;
|
||||
}).when(mLockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle);
|
||||
|
||||
// Run checkNewCredentialFromActivityResult()
|
||||
final Intent intent = new Intent().putExtra(EXTRA_KEY_GK_PW_HANDLE, gkPwHandle);
|
||||
final boolean ret = mViewModel.checkNewCredentialFromActivityResult(false,
|
||||
new ActivityResult(Activity.RESULT_OK, intent));
|
||||
|
||||
assertThat(ret).isTrue();
|
||||
assertThat(mViewModel.getGenerateChallengeFailedLiveData().getValue()).isNull();
|
||||
assertThat(mViewModel.getToken()).isNotNull();
|
||||
assertThat(mChallengeGenerator.mCallbackRunCount).isEqualTo(1);
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue();
|
||||
}
|
||||
|
||||
public static class TestChallengeGenerator implements ChallengeGenerator {
|
||||
public int mSensorId = -1;
|
||||
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();
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse newBadCredential(int timeout) {
|
||||
if (timeout > 0) {
|
||||
return VerifyCredentialResponse.fromTimeout(timeout);
|
||||
} else {
|
||||
return VerifyCredentialResponse.fromError();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 android.app.Activity
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.os.UserHandle
|
||||
import androidx.activity.result.ActivityResult
|
||||
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.biometrics.BiometricEnrollBase
|
||||
import com.android.settings.biometrics2.ui.model.CredentialModel
|
||||
import com.android.settings.biometrics2.ui.model.CredentialModelTest.Companion.newGkPwHandleCredentialIntentExtras
|
||||
import com.android.settings.biometrics2.ui.model.CredentialModelTest.Companion.newOnlySensorValidCredentialIntentExtras
|
||||
import com.android.settings.biometrics2.ui.model.CredentialModelTest.Companion.newValidTokenCredentialIntentExtras
|
||||
import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.ChallengeGenerator
|
||||
import com.android.settings.password.ChooseLockPattern
|
||||
import com.android.settings.password.ChooseLockSettingsHelper
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.junit.MockitoRule
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AutoCredentialViewModelTest {
|
||||
|
||||
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
|
||||
|
||||
@Mock private lateinit var lockPatternUtils: LockPatternUtils
|
||||
|
||||
private var challengeGenerator: TestChallengeGenerator = TestChallengeGenerator()
|
||||
|
||||
private lateinit var viewModel: AutoCredentialViewModel
|
||||
private fun newAutoCredentialViewModel(bundle: Bundle?): AutoCredentialViewModel {
|
||||
return AutoCredentialViewModel(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
lockPatternUtils,
|
||||
challengeGenerator,
|
||||
CredentialModel(bundle, SystemClock.elapsedRealtimeClock())
|
||||
)
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
challengeGenerator = TestChallengeGenerator()
|
||||
}
|
||||
|
||||
private fun setupGenerateChallenge(userId: Int, newSensorId: Int, newChallenge: Long) {
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
challengeGenerator.userId = userId
|
||||
challengeGenerator.sensorId = newSensorId
|
||||
challengeGenerator.challenge = newChallenge
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_validCredentialCase() = runTest {
|
||||
val userId = 99
|
||||
viewModel = newAutoCredentialViewModel(newValidTokenCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.CREDENTIAL_VALID)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_needToChooseLock() = runTest {
|
||||
val userId = 100
|
||||
viewModel = newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
|
||||
)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.FAIL_NEED_TO_CHOOSE_LOCK)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_needToConfirmLockForSomething() = runTest {
|
||||
val userId = 101
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_needToConfirmLockForNumeric() = runTest {
|
||||
val userId = 102
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|
||||
)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_needToConfirmLockForAlphabetic() = runTest {
|
||||
val userId = 103
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
|
||||
)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(this)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_generateChallenge() = runTest {
|
||||
val userId = 104
|
||||
val gkPwHandle = 1111L
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
val newSensorId = 10
|
||||
val newChallenge = 20L
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge)
|
||||
whenever(
|
||||
lockPatternUtils.verifyGatekeeperPasswordHandle(
|
||||
gkPwHandle,
|
||||
newChallenge,
|
||||
userId
|
||||
)
|
||||
)
|
||||
.thenReturn(newGoodCredential(gkPwHandle, byteArrayOf(1)))
|
||||
val hasCalledRemoveGkPwHandle = AtomicBoolean()
|
||||
Mockito.doAnswer {
|
||||
hasCalledRemoveGkPwHandle.set(true)
|
||||
null
|
||||
}.`when`(lockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(backgroundScope)
|
||||
runCurrent()
|
||||
|
||||
// Check viewModel behavior
|
||||
assertThat(action).isEqualTo(CredentialAction.IS_GENERATING_CHALLENGE)
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
|
||||
// Check data inside CredentialModel
|
||||
assertThat(viewModel.token).isNotNull()
|
||||
assertThat(challengeGenerator.callbackRunCount).isEqualTo(1)
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isFalse()
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
val generatingChallengeExtras = viewModel.createGeneratingChallengeExtras()
|
||||
assertThat(generatingChallengeExtras).isNotNull()
|
||||
assertThat(generatingChallengeExtras!!.getLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE))
|
||||
.isEqualTo(newChallenge)
|
||||
val tokens =
|
||||
generatingChallengeExtras.getByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN)
|
||||
assertThat(tokens).isNotNull()
|
||||
assertThat(tokens!!.size).isEqualTo(1)
|
||||
assertThat(tokens[0]).isEqualTo(1)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckCredential_generateChallengeFail() = runTest {
|
||||
backgroundScope.launch {
|
||||
val userId = 104
|
||||
val gkPwHandle = 1111L
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
val newSensorId = 10
|
||||
val newChallenge = 20L
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge)
|
||||
whenever(
|
||||
lockPatternUtils.verifyGatekeeperPasswordHandle(
|
||||
gkPwHandle,
|
||||
newChallenge,
|
||||
userId
|
||||
)
|
||||
)
|
||||
.thenReturn(newBadCredential(0))
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run credential check
|
||||
val action = viewModel.checkCredential(this)
|
||||
runCurrent()
|
||||
|
||||
assertThat(action).isEqualTo(CredentialAction.IS_GENERATING_CHALLENGE)
|
||||
assertThat(generateFails.size).isEqualTo(1)
|
||||
assertThat(generateFails[0]).isEqualTo(true)
|
||||
assertThat(challengeGenerator.callbackRunCount).isEqualTo(1)
|
||||
|
||||
// Check createGeneratingChallengeExtras()
|
||||
assertThat(viewModel.createGeneratingChallengeExtras()).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetUserId_fromIntent() {
|
||||
val userId = 106
|
||||
viewModel = newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
|
||||
// Get userId
|
||||
assertThat(viewModel.userId).isEqualTo(userId)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_invalidChooseLock() = runTest {
|
||||
backgroundScope.launch {
|
||||
val userId = 107
|
||||
val gkPwHandle = 3333L
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle))
|
||||
val intent = Intent()
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
true,
|
||||
ActivityResult(ChooseLockPattern.RESULT_FINISHED + 1, intent),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isFalse()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_invalidConfirmLock() = runTest {
|
||||
backgroundScope.launch {
|
||||
val userId = 107
|
||||
val gkPwHandle = 3333L
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle))
|
||||
val intent = Intent()
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
false,
|
||||
ActivityResult(Activity.RESULT_OK + 1, intent),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isFalse()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_nullDataChooseLock() = runTest {
|
||||
val userId = 108
|
||||
val gkPwHandle = 4444L
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newGkPwHandleCredentialIntentExtras(userId, gkPwHandle))
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
true,
|
||||
ActivityResult(ChooseLockPattern.RESULT_FINISHED, null),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isFalse()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_nullDataConfirmLock() = runTest {
|
||||
val userId = 109
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
false,
|
||||
ActivityResult(Activity.RESULT_OK, null),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isFalse()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_validChooseLock() = runTest {
|
||||
val userId = 108
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
val gkPwHandle = 6666L
|
||||
val newSensorId = 50
|
||||
val newChallenge = 60L
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge)
|
||||
whenever(
|
||||
lockPatternUtils.verifyGatekeeperPasswordHandle(
|
||||
gkPwHandle,
|
||||
newChallenge,
|
||||
userId
|
||||
)
|
||||
)
|
||||
.thenReturn(newGoodCredential(gkPwHandle, byteArrayOf(1)))
|
||||
val hasCalledRemoveGkPwHandle = AtomicBoolean()
|
||||
Mockito.doAnswer {
|
||||
hasCalledRemoveGkPwHandle.set(true)
|
||||
null
|
||||
}.`when`(lockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val intent =
|
||||
Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle)
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
true,
|
||||
ActivityResult(ChooseLockPattern.RESULT_FINISHED, intent),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isTrue()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
assertThat(viewModel.token).isNotNull()
|
||||
assertThat(challengeGenerator.callbackRunCount).isEqualTo(1)
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testGenerateChallengeAsCredentialActivityResult_validConfirmLock() = runTest {
|
||||
val userId = 109
|
||||
viewModel =
|
||||
newAutoCredentialViewModel(newOnlySensorValidCredentialIntentExtras(userId))
|
||||
whenever(lockPatternUtils.getActivePasswordQuality(userId)).thenReturn(
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
)
|
||||
val gkPwHandle = 5555L
|
||||
val newSensorId = 80
|
||||
val newChallenge = 90L
|
||||
setupGenerateChallenge(userId, newSensorId, newChallenge)
|
||||
whenever(
|
||||
lockPatternUtils.verifyGatekeeperPasswordHandle(
|
||||
gkPwHandle,
|
||||
newChallenge,
|
||||
userId
|
||||
)
|
||||
)
|
||||
.thenReturn(newGoodCredential(gkPwHandle, byteArrayOf(1)))
|
||||
val hasCalledRemoveGkPwHandle = AtomicBoolean()
|
||||
Mockito.doAnswer {
|
||||
hasCalledRemoveGkPwHandle.set(true)
|
||||
null
|
||||
}.`when`(lockPatternUtils).removeGatekeeperPasswordHandle(gkPwHandle)
|
||||
|
||||
val generateFails = listOfGenerateChallengeFailedFlow()
|
||||
|
||||
// Run generateChallengeAsCredentialActivityResult()
|
||||
val intent =
|
||||
Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle)
|
||||
val ret = viewModel.generateChallengeAsCredentialActivityResult(
|
||||
false,
|
||||
ActivityResult(Activity.RESULT_OK, intent),
|
||||
backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(ret).isTrue()
|
||||
assertThat(generateFails.size).isEqualTo(0)
|
||||
assertThat(viewModel.token).isNotNull()
|
||||
assertThat(challengeGenerator.callbackRunCount).isEqualTo(1)
|
||||
assertThat(hasCalledRemoveGkPwHandle.get()).isTrue()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun TestScope.listOfGenerateChallengeFailedFlow(): List<Boolean> =
|
||||
mutableListOf<Boolean>().also {
|
||||
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.generateChallengeFailedFlow.toList(it)
|
||||
}
|
||||
}
|
||||
|
||||
class TestChallengeGenerator : ChallengeGenerator {
|
||||
var sensorId = -1
|
||||
var userId = UserHandle.myUserId()
|
||||
var challenge = CredentialModel.INVALID_CHALLENGE
|
||||
var callbackRunCount = 0
|
||||
|
||||
private var _callback: AutoCredentialViewModel.GenerateChallengeCallback? = null
|
||||
|
||||
override fun getCallback(): AutoCredentialViewModel.GenerateChallengeCallback? {
|
||||
return _callback
|
||||
}
|
||||
|
||||
override fun setCallback(callback: AutoCredentialViewModel.GenerateChallengeCallback?) {
|
||||
_callback = callback
|
||||
}
|
||||
|
||||
override fun generateChallenge(userId: Int) {
|
||||
val callback = _callback ?: return
|
||||
callback.onChallengeGenerated(sensorId, this.userId, challenge)
|
||||
++callbackRunCount
|
||||
}
|
||||
}
|
||||
|
||||
private fun newGoodCredential(gkPwHandle: Long, hat: ByteArray): VerifyCredentialResponse {
|
||||
return VerifyCredentialResponse.Builder()
|
||||
.setGatekeeperPasswordHandle(gkPwHandle)
|
||||
.setGatekeeperHAT(hat)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun newBadCredential(timeout: Int): VerifyCredentialResponse {
|
||||
return if (timeout > 0) {
|
||||
VerifyCredentialResponse.fromTimeout(timeout)
|
||||
} else {
|
||||
VerifyCredentialResponse.fromError()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,12 +23,20 @@ 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.biometrics.BiometricEnrollBase
|
||||
import com.android.settings.biometrics2.data.repository.FingerprintRepository
|
||||
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest
|
||||
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwRequest
|
||||
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository
|
||||
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints
|
||||
import com.android.settings.testutils.InstantTaskExecutorRule
|
||||
import com.google.common.truth.Truth
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -42,8 +50,6 @@ class FingerprintEnrollmentViewModelTest {
|
||||
|
||||
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
|
||||
|
||||
@get:Rule val taskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
private val application: Application
|
||||
get() = ApplicationProvider.getApplicationContext()
|
||||
|
||||
@@ -69,12 +75,12 @@ class FingerprintEnrollmentViewModelTest {
|
||||
|
||||
@Test
|
||||
fun testGetRequest() {
|
||||
Truth.assertThat(viewModel.request).isNotNull()
|
||||
assertThat(viewModel.request).isNotNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIsWaitingActivityResultDefaultFalse() {
|
||||
Truth.assertThat(viewModel.isWaitingActivityResult.value).isFalse()
|
||||
assertThat(viewModel.isWaitingActivityResult.value).isFalse()
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +89,8 @@ class FingerprintEnrollmentViewModelTest {
|
||||
val retResult = viewModel.getOverrideActivityResult(
|
||||
ActivityResult(22, null), null
|
||||
)
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
Truth.assertThat(retResult.data).isNull()
|
||||
assertThat(retResult).isNotNull()
|
||||
assertThat(retResult.data).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,8 +99,8 @@ class FingerprintEnrollmentViewModelTest {
|
||||
val retResult = viewModel.getOverrideActivityResult(
|
||||
ActivityResult(33, intent), null
|
||||
)
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
Truth.assertThat(retResult.data).isEqualTo(intent)
|
||||
assertThat(retResult).isNotNull()
|
||||
assertThat(retResult.data).isEqualTo(intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,8 +112,8 @@ class FingerprintEnrollmentViewModelTest {
|
||||
ActivityResult(33, null), extra
|
||||
)
|
||||
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
Truth.assertThat(retResult.data).isNull()
|
||||
assertThat(retResult).isNotNull()
|
||||
assertThat(retResult.data).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,16 +130,16 @@ class FingerprintEnrollmentViewModelTest {
|
||||
val retResult = viewModel.getOverrideActivityResult(
|
||||
ActivityResult(33, null), extra
|
||||
)
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
assertThat(retResult).isNotNull()
|
||||
|
||||
val retIntent = retResult.data
|
||||
Truth.assertThat(retIntent).isNotNull()
|
||||
assertThat(retIntent).isNotNull()
|
||||
|
||||
val retExtra = retIntent!!.extras
|
||||
Truth.assertThat(retExtra).isNotNull()
|
||||
Truth.assertThat(retExtra!!.size).isEqualTo(extra.size)
|
||||
Truth.assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1))
|
||||
Truth.assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2))
|
||||
assertThat(retExtra).isNotNull()
|
||||
assertThat(retExtra!!.size).isEqualTo(extra.size)
|
||||
assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1))
|
||||
assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,15 +155,15 @@ class FingerprintEnrollmentViewModelTest {
|
||||
|
||||
val retResult = viewModel.getOverrideActivityResult(ActivityResult(33, intent), extra)
|
||||
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
assertThat(retResult).isNotNull()
|
||||
|
||||
val retIntent = retResult.data
|
||||
Truth.assertThat(retIntent).isNotNull()
|
||||
assertThat(retIntent).isNotNull()
|
||||
|
||||
val retExtra = retIntent!!.extras
|
||||
Truth.assertThat(retExtra).isNotNull()
|
||||
Truth.assertThat(retExtra!!.size).isEqualTo(intent.extras!!.size)
|
||||
Truth.assertThat(retExtra.getString(key2)).isEqualTo(intent.extras!!.getString(key2))
|
||||
assertThat(retExtra).isNotNull()
|
||||
assertThat(retExtra!!.size).isEqualTo(intent.extras!!.size)
|
||||
assertThat(retExtra.getString(key2)).isEqualTo(intent.extras!!.getString(key2))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -177,17 +183,17 @@ class FingerprintEnrollmentViewModelTest {
|
||||
viewModel.isNewFingerprintAdded = true
|
||||
|
||||
val retResult = viewModel.getOverrideActivityResult(ActivityResult(33, intent), extra)
|
||||
Truth.assertThat(retResult).isNotNull()
|
||||
assertThat(retResult).isNotNull()
|
||||
|
||||
val retIntent = retResult.data
|
||||
Truth.assertThat(retIntent).isNotNull()
|
||||
assertThat(retIntent).isNotNull()
|
||||
|
||||
val retExtra = retIntent!!.extras
|
||||
Truth.assertThat(retExtra).isNotNull()
|
||||
Truth.assertThat(retExtra!!.size).isEqualTo(extra.size + intent.extras!!.size)
|
||||
Truth.assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1))
|
||||
Truth.assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2))
|
||||
Truth.assertThat(retExtra.getLong(key3)).isEqualTo(intent.extras!!.getLong(key3))
|
||||
assertThat(retExtra).isNotNull()
|
||||
assertThat(retExtra!!.size).isEqualTo(extra.size + intent.extras!!.size)
|
||||
assertThat(retExtra.getString(key1)).isEqualTo(extra.getString(key1))
|
||||
assertThat(retExtra.getInt(key2)).isEqualTo(extra.getInt(key2))
|
||||
assertThat(retExtra.getLong(key3)).isEqualTo(intent.extras!!.getLong(key3))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -205,18 +211,120 @@ class FingerprintEnrollmentViewModelTest {
|
||||
)
|
||||
|
||||
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 0)
|
||||
Truth.assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
|
||||
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 1)
|
||||
Truth.assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
|
||||
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 2)
|
||||
Truth.assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
|
||||
|
||||
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 3)
|
||||
Truth.assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
|
||||
assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
|
||||
|
||||
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 4)
|
||||
Truth.assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
|
||||
assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testSetResultFlow_defaultEmpty() = runTest {
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckFinishActivityDuringOnPause_doNothingIfIsSuw() = runTest {
|
||||
viewModel = FingerprintEnrollmentViewModel(
|
||||
application,
|
||||
fingerprintRepository,
|
||||
newIsSuwRequest(application)
|
||||
)
|
||||
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
viewModel.checkFinishActivityDuringOnPause(
|
||||
isActivityFinishing = false,
|
||||
isChangingConfigurations = false,
|
||||
scope = this
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckFinishActivityDuringOnPause_doNothingIfIsWaitingActivity() = runTest {
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
viewModel.isWaitingActivityResult.value = true
|
||||
viewModel.checkFinishActivityDuringOnPause(
|
||||
isActivityFinishing = false,
|
||||
isChangingConfigurations = false,
|
||||
scope = this
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckFinishActivityDuringOnPause_doNothingIfIsActivityFinishing() = runTest {
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
viewModel.checkFinishActivityDuringOnPause(
|
||||
isActivityFinishing = true,
|
||||
isChangingConfigurations = false,
|
||||
scope = this
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckFinishActivityDuringOnPause_doNothingIfIsChangingConfigurations() = runTest {
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
viewModel.checkFinishActivityDuringOnPause(
|
||||
isActivityFinishing = false,
|
||||
isChangingConfigurations = true,
|
||||
scope = this
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testCheckFinishActivityDuringOnPause_defaultFinishSelf() = runTest {
|
||||
val activityResults = listOfSetResultFlow()
|
||||
|
||||
viewModel.checkFinishActivityDuringOnPause(
|
||||
isActivityFinishing = false,
|
||||
isChangingConfigurations = false,
|
||||
scope = backgroundScope
|
||||
)
|
||||
runCurrent()
|
||||
|
||||
assertThat(activityResults.size).isEqualTo(1)
|
||||
assertThat(activityResults[0].resultCode).isEqualTo(BiometricEnrollBase.RESULT_TIMEOUT)
|
||||
assertThat(activityResults[0].data).isEqualTo(null)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun TestScope.listOfSetResultFlow(): List<ActivityResult> =
|
||||
mutableListOf<ActivityResult>().also {
|
||||
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.setResultFlow.toList(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user