Merge 24Q4 (ab/12406339) into aosp-main-future

Bug: 370570306
Merged-In: Ie90e7495dd4a134538bae6e3e08eea0d02134b14
Change-Id: I20517e9ee410e95f2cbeb1247c0c0288ed9f006f
This commit is contained in:
Xin Li
2024-11-11 21:38:40 -08:00
1597 changed files with 77072 additions and 46403 deletions

View File

@@ -32,7 +32,7 @@ android_test {
"truth",
"kotlinx_coroutines_test",
"Settings-testutils2",
"MediaDrmSettingsFlagsLib",
"servicestests-utils",
// Don't add SettingsLib libraries here - you can use them directly as they are in the
// instrumented Settings app.
],

View File

@@ -1,109 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class ResetSubscriptionContractTest {
private static final int SUB_ID_1 = 3;
private static final int SUB_ID_2 = 8;
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
@Mock
private SubscriptionInfo mSubscriptionInfo1;
@Mock
private SubscriptionInfo mSubscriptionInfo2;
private Context mContext;
private ResetNetworkRequest mRequestArgs;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mRequestArgs = new ResetNetworkRequest(new Bundle());
}
private ResetSubscriptionContract createTestObject() {
return new ResetSubscriptionContract(mContext, mRequestArgs) {
@Override
protected SubscriptionManager getSubscriptionManager() {
return mSubscriptionManager;
}
@Override
protected OnSubscriptionsChangedListener getChangeListener() {
return mOnSubscriptionsChangedListener;
}
};
}
@Test
public void getAnyMissingSubscriptionId_returnNull_whenNoSubscriptionChange() {
mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1);
doReturn(mSubscriptionInfo1).when(mSubscriptionManager)
.getActiveSubscriptionInfo(SUB_ID_1);
mRequestArgs.setResetApn(SUB_ID_2);
doReturn(mSubscriptionInfo2).when(mSubscriptionManager)
.getActiveSubscriptionInfo(SUB_ID_2);
ResetSubscriptionContract target = createTestObject();
verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any());
assertNull(target.getAnyMissingSubscriptionId());
}
@Test
public void getAnyMissingSubscriptionId_returnSubId_whenSubscriptionNotActive() {
mRequestArgs.setResetTelephonyAndNetworkPolicyManager(SUB_ID_1);
doReturn(mSubscriptionInfo1).when(mSubscriptionManager)
.getActiveSubscriptionInfo(SUB_ID_1);
mRequestArgs.setResetApn(SUB_ID_2);
doReturn(null).when(mSubscriptionManager)
.getActiveSubscriptionInfo(SUB_ID_2);
ResetSubscriptionContract target = createTestObject();
verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), any());
assertEquals(target.getAnyMissingSubscriptionId(), new Integer(SUB_ID_2));
}
}

View File

@@ -16,12 +16,18 @@
package com.android.settings.accessibility;
import static android.view.flags.Flags.FLAG_ENABLE_VECTOR_CURSOR_A11Y_SETTINGS;
import static com.android.settings.accessibility.LargePointerIconPreferenceController.OFF;
import static com.android.settings.accessibility.LargePointerIconPreferenceController.ON;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
@@ -31,12 +37,16 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class LargePointerIconPreferenceControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final int UNKNOWN = -1;
private Context mContext;
@@ -51,9 +61,17 @@ public class LargePointerIconPreferenceControllerTest {
}
@Test
@RequiresFlagsDisabled(FLAG_ENABLE_VECTOR_CURSOR_A11Y_SETTINGS)
public void getAvailabilityStatus_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
@RequiresFlagsEnabled(FLAG_ENABLE_VECTOR_CURSOR_A11Y_SETTINGS)
public void getAvailabilityStatus_shouldReturnConditionallyUnavailable() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
@Test

View File

@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -24,7 +26,12 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.view.accessibility.Flags;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -33,6 +40,7 @@ import com.android.internal.R;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,6 +48,8 @@ import org.junit.runner.RunWith;
public class ReduceBrightColorsPreferenceControllerTest {
private static final String PREF_KEY = "rbc_preference";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private Context mContext;
private Resources mResources;;
private ReduceBrightColorsPreferenceController mController;
@@ -88,6 +98,20 @@ public class ReduceBrightColorsPreferenceControllerTest {
assertThat(mController.isAvailable()).isFalse();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_A11Y_QS_SHORTCUT)
public void getTileComponentName_a11yQsFlagOff_returnComponentName() {
assertThat(mController.getTileComponentName())
.isEqualTo(REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_A11Y_QS_SHORTCUT)
public void getTileComponentName_a11yQsFlagOff_returnNull() {
assertThat(mController.getTileComponentName()).isNull();
}
private int resourceId(String type, String name) {
return mContext.getResources().getIdentifier(name, type, mContext.getPackageName());
}

View File

@@ -1 +0,0 @@
include /src/com/android/settings/biometrics/OWNERS

View File

@@ -1,203 +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.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.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupSuwMaxFingerprintsEnrollable;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
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.ArrayList;
@RunWith(AndroidJUnit4.class)
public class FingerprintRepositoryTest {
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Mock private Resources mResources;
@Mock private FingerprintManager mFingerprintManager;
private Context mContext;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
}
@Test
public void testCanAssumeSensorType_forUnknownSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 1);
assertThat(repository.canAssumeUdfps()).isFalse();
assertThat(repository.canAssumeSfps()).isFalse();
}
@Test
public void testCanAssumeSensorType_forRearSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_REAR, 1);
assertThat(repository.canAssumeUdfps()).isFalse();
assertThat(repository.canAssumeSfps()).isFalse();
}
@Test
public void testCanAssumeSensorType_forUdfpsUltrasonicSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UDFPS_ULTRASONIC, 1);
assertThat(repository.canAssumeUdfps()).isTrue();
assertThat(repository.canAssumeSfps()).isFalse();
}
@Test
public void testCanAssumeSensorType_forUdfpsOpticalSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UDFPS_OPTICAL, 1);
assertThat(repository.canAssumeUdfps()).isTrue();
assertThat(repository.canAssumeSfps()).isFalse();
}
@Test
public void testCanAssumeSensorType_forPowerButtonSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_POWER_BUTTON, 1);
assertThat(repository.canAssumeUdfps()).isFalse();
assertThat(repository.canAssumeSfps()).isTrue();
}
@Test
public void testCanAssumeSensorType_forHomeButtonSensor() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_HOME_BUTTON, 1);
assertThat(repository.canAssumeUdfps()).isFalse();
assertThat(repository.canAssumeSfps()).isFalse();
}
@Test
public void testGetMaxFingerprints() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 999);
assertThat(repository.getMaxFingerprints()).isEqualTo(999);
}
@Test
public void testGetNumOfEnrolledFingerprintsSize() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 999);
setupFingerprintEnrolledFingerprints(mFingerprintManager, 10, 3);
setupFingerprintEnrolledFingerprints(mFingerprintManager, 22, 99);
assertThat(repository.getNumOfEnrolledFingerprintsSize(10)).isEqualTo(3);
assertThat(repository.getNumOfEnrolledFingerprintsSize(22)).isEqualTo(99);
}
@Test
public void testGetMaxFingerprintsInSuw() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 999);
setupSuwMaxFingerprintsEnrollable(mContext, mResources, 333);
assertThat(repository.getMaxFingerprintsInSuw(mResources))
.isEqualTo(333);
setupSuwMaxFingerprintsEnrollable(mContext, mResources, 20);
assertThat(repository.getMaxFingerprintsInSuw(mResources)).isEqualTo(20);
}
@Test
public void testGetFirstFingerprintSensorPropertiesInternal() {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5,
new ArrayList<>() /* componentInfo */,
TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */);
props.add(prop);
doAnswer(invocation -> {
final IFingerprintAuthenticatorsRegisteredCallback callback =
invocation.getArgument(0);
callback.onAllAuthenticatorsRegistered(props);
return null;
}).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
final FingerprintRepository repository = new FingerprintRepository(mFingerprintManager);
assertThat(repository.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
}
@Test
public void testGetEnrollStageCount() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 999);
final int expectedValue = 24;
doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
assertThat(repository.getEnrollStageCount()).isEqualTo(expectedValue);
}
@Test
public void testGetEnrollStageThreshold() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UNKNOWN, 999);
final float expectedValue0 = 0.42f;
final float expectedValue1 = 0.24f;
final float expectedValue2 = 0.33f;
final float expectedValue3 = 0.90f;
doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
assertThat(repository.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
assertThat(repository.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
assertThat(repository.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
assertThat(repository.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
}
}

View File

@@ -1,136 +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.model
import android.content.Intent
import android.os.Bundle
import android.os.SystemClock
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics.BiometricEnrollBase
import com.android.settings.password.ChooseLockSettingsHelper
import com.google.common.truth.Truth
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Arrays
@RunWith(AndroidJUnit4::class)
class CredentialModelTest {
private val clock = SystemClock.elapsedRealtimeClock()
@Test
fun testNullBundle() {
val credentialModel = CredentialModel(null, clock)
Truth.assertThat(credentialModel.userId).isEqualTo(UserHandle.myUserId())
}
companion object {
@JvmStatic
fun newCredentialModelIntentExtras(
userId: Int, challenge: Long,
token: ByteArray?, gkPwHandle: Long
): Bundle {
val bundle = Bundle()
bundle.putInt(Intent.EXTRA_USER_ID, userId)
bundle.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge)
bundle.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token)
bundle.putLong(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, gkPwHandle)
return bundle
}
@JvmStatic
fun newValidTokenCredentialIntentExtras(userId: Int): Bundle {
return newCredentialModelIntentExtras(
userId, 1L, byteArrayOf(0, 1, 2),
CredentialModel.INVALID_GK_PW_HANDLE
)
}
@JvmStatic
fun newOnlySensorValidCredentialIntentExtras(userId: Int): Bundle {
return newCredentialModelIntentExtras(
userId, CredentialModel.INVALID_CHALLENGE, null,
CredentialModel.INVALID_GK_PW_HANDLE
)
}
@JvmStatic
fun newGkPwHandleCredentialIntentExtras(userId: Int, gkPwHandle: Long): Bundle {
return newCredentialModelIntentExtras(
userId,
CredentialModel.INVALID_CHALLENGE,
null,
gkPwHandle
)
}
private fun checkBundleLongValue(
bundle1: Bundle, bundle2: Bundle,
key: String
) {
if (!bundle1.containsKey(key)) {
return
}
val value1 = bundle1.getInt(key)
val value2 = bundle2.getInt(key)
Truth.assertWithMessage(
"bundle not match, key:" + key + ", value1:" + value1 + ", value2:"
+ value2
).that(value1).isEqualTo(value2)
}
private fun checkBundleIntValue(
bundle1: Bundle, bundle2: Bundle,
key: String
) {
if (!bundle1.containsKey(key)) {
return
}
val value1 = bundle1.getLong(key)
val value2 = bundle2.getLong(key)
Truth.assertWithMessage(
"bundle not match, key:" + key + ", value1:" + value1 + ", value2:"
+ value2
).that(value1).isEqualTo(value2)
}
private fun checkBundleByteArrayValue(
bundle1: Bundle, bundle2: Bundle,
key: String
) {
if (!bundle1.containsKey(key)) {
return
}
val value1 = bundle1.getByteArray(key)
val value2 = bundle2.getByteArray(key)
val errMsg = ("bundle not match, key:" + key + ", value1:" + Arrays.toString(value1)
+ ", value2:" + Arrays.toString(value2))
if (value1 == null) {
Truth.assertWithMessage(errMsg).that(value2).isNull()
} else {
Truth.assertWithMessage(errMsg).that(value1.size).isEqualTo(
value2!!.size
)
for (i in value1.indices) {
Truth.assertWithMessage(errMsg).that(value1[i]).isEqualTo(
value2[i]
)
}
}
}
}
}

View File

@@ -1,175 +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.model
import android.content.Context
import android.content.Intent
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics.BiometricEnrollActivity
import com.google.android.setupcompat.util.WizardManagerHelper
import com.google.common.truth.Truth
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class EnrollmentRequestTest {
private val context = ApplicationProvider.getApplicationContext<Context>()
@Test
fun testIsSuw() {
// Default false
Truth.assertThat(EnrollmentRequest(Intent(), context, true).isSuw).isFalse()
Truth.assertThat(EnrollmentRequest(Intent(), context, false).isSuw).isFalse()
val trueIntent = Intent()
trueIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true)
Truth.assertThat(EnrollmentRequest(trueIntent, context, true).isSuw).isTrue()
Truth.assertThat(EnrollmentRequest(trueIntent, context, false).isSuw).isFalse()
val falseIntent = Intent()
trueIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, false)
Truth.assertThat(EnrollmentRequest(falseIntent, context, true).isSuw).isFalse()
Truth.assertThat(EnrollmentRequest(falseIntent, context, false).isSuw).isFalse()
}
@Test
fun testIsAfterSuwOrSuwSuggestedAction() {
// Default false
Truth.assertThat(
EnrollmentRequest(Intent(), context, true)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
Truth.assertThat(
EnrollmentRequest(Intent(), context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val deferredTrueIntent = Intent()
deferredTrueIntent.putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, true)
Truth.assertThat(
EnrollmentRequest(deferredTrueIntent, context, true)
.isAfterSuwOrSuwSuggestedAction
).isTrue()
Truth.assertThat(
EnrollmentRequest(deferredTrueIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val deferredFalseIntent = Intent()
deferredFalseIntent.putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, false)
Truth.assertThat(
EnrollmentRequest(deferredFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
Truth.assertThat(
EnrollmentRequest(deferredFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val portalTrueIntent = Intent()
portalTrueIntent.putExtra(WizardManagerHelper.EXTRA_IS_PORTAL_SETUP, true)
Truth.assertThat(
EnrollmentRequest(portalTrueIntent, context, true)
.isAfterSuwOrSuwSuggestedAction
).isTrue()
Truth.assertThat(
EnrollmentRequest(portalTrueIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val portalFalseIntent = Intent()
portalFalseIntent.putExtra(WizardManagerHelper.EXTRA_IS_PORTAL_SETUP, false)
Truth.assertThat(
EnrollmentRequest(portalFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
Truth.assertThat(
EnrollmentRequest(portalFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val suggestedTrueIntent = Intent()
suggestedTrueIntent.putExtra(WizardManagerHelper.EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW, true)
Truth.assertThat(
EnrollmentRequest(suggestedTrueIntent, context, true)
.isAfterSuwOrSuwSuggestedAction
).isTrue()
Truth.assertThat(
EnrollmentRequest(suggestedTrueIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
val suggestedFalseIntent = Intent()
suggestedFalseIntent.putExtra(WizardManagerHelper.EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW, false)
Truth.assertThat(
EnrollmentRequest(suggestedFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
Truth.assertThat(
EnrollmentRequest(suggestedFalseIntent, context, false)
.isAfterSuwOrSuwSuggestedAction
).isFalse()
}
@Test
fun testGetSuwExtras_inSuw() {
val suwIntent = Intent()
suwIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true)
val setupRequest = EnrollmentRequest(suwIntent, context, true)
val bundle = setupRequest.suwExtras
Truth.assertThat(bundle).isNotNull()
Truth.assertThat(bundle.size()).isAtLeast(1)
Truth.assertThat(bundle.getBoolean(WizardManagerHelper.EXTRA_IS_SETUP_FLOW)).isTrue()
}
@Test
fun testGetSuwExtras_notInSuw() {
val suwIntent = Intent()
suwIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true)
val setupRequest = EnrollmentRequest(suwIntent, context, false)
val bundle = setupRequest.suwExtras
Truth.assertThat(bundle).isNotNull()
Truth.assertThat(bundle.size()).isEqualTo(0)
}
@Test
fun testIsSkipIntro() {
// Default false
Truth.assertThat(EnrollmentRequest(Intent(), context, true).isSkipIntro).isFalse()
Truth.assertThat(EnrollmentRequest(Intent(), context, false).isSkipIntro).isFalse()
val trueIntent = Intent()
trueIntent.putExtra(BiometricEnrollActivity.EXTRA_SKIP_INTRO, true)
Truth.assertThat(EnrollmentRequest(trueIntent, context, true).isSkipIntro).isTrue()
Truth.assertThat(EnrollmentRequest(trueIntent, context, false).isSkipIntro).isTrue()
val falseIntent = Intent()
falseIntent.putExtra(BiometricEnrollActivity.EXTRA_SKIP_INTRO, false)
Truth.assertThat(EnrollmentRequest(falseIntent, context, false).isSkipIntro).isFalse()
Truth.assertThat(EnrollmentRequest(falseIntent, context, false).isSkipIntro).isFalse()
}
@Test
fun testIsSkipFindSensor() {
// Default false
Truth.assertThat(EnrollmentRequest(Intent(), context, true).isSkipFindSensor)
.isFalse()
Truth.assertThat(EnrollmentRequest(Intent(), context, false).isSkipFindSensor)
.isFalse()
val trueIntent = Intent()
trueIntent.putExtra(EnrollmentRequest.EXTRA_SKIP_FIND_SENSOR, true)
Truth.assertThat(EnrollmentRequest(trueIntent, context, true).isSkipFindSensor).isTrue()
Truth.assertThat(EnrollmentRequest(trueIntent, context, false).isSkipFindSensor).isTrue()
val falseIntent = Intent()
falseIntent.putExtra(EnrollmentRequest.EXTRA_SKIP_FIND_SENSOR, false)
Truth.assertThat(EnrollmentRequest(falseIntent, context, false).isSkipFindSensor)
.isFalse()
Truth.assertThat(EnrollmentRequest(falseIntent, context, false).isSkipFindSensor)
.isFalse()
}
}

View File

@@ -1,519 +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 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 java.util.concurrent.atomic.AtomicBoolean
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 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
}
@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()
}
@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()
}
@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()
}
@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()
}
@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()
}
@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)
}
@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)
}
@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)
}
}
@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)
}
}
@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)
}
@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)
}
@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()
}
@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()
}
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
override var callback: AutoCredentialViewModel.GenerateChallengeCallback? = null
override fun generateChallenge(userId: Int) {
callback?.let {
it.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()
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics2.ui.viewmodel;
import static com.google.common.truth.Truth.assertThat;
import android.app.Application;
import android.content.res.Configuration;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.testutils.InstantTaskExecutorRule;
import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DeviceFoldedViewModelTest {
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
private DeviceFoldedViewModel mViewModel;
@Before
public void setUp() {
final Application application = ApplicationProvider.getApplicationContext();
mViewModel = new DeviceFoldedViewModel(new ScreenSizeFoldProvider(application),
application.getMainExecutor());
}
@Test
public void testLiveData() {
final Configuration config1 = new Configuration();
config1.smallestScreenWidthDp = 601;
mViewModel.onConfigurationChanged(config1);
assertThat(mViewModel.getLiveData().getValue()).isFalse();
final Configuration config2 = new Configuration();
config2.smallestScreenWidthDp = 599;
mViewModel.onConfigurationChanged(config2);
assertThat(mViewModel.getLiveData().getValue()).isTrue();
}
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics2.ui.viewmodel;
import static com.google.common.truth.Truth.assertThat;
import android.app.Application;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
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.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class DeviceRotationViewModelTest {
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
private TestDeviceRotationViewModel mViewModel;
@Before
public void setUp() {
TestDeviceRotationViewModel.sTestRotation = 3;
mViewModel = new TestDeviceRotationViewModel(ApplicationProvider.getApplicationContext());
}
@Test
public void testDefaultLiveDataNotNull() {
assertThat(mViewModel.getLiveData().getValue()).isEqualTo(mViewModel.sTestRotation);
}
@Test
public void testOnDisplayChange() {
mViewModel.sTestRotation = 3;
mViewModel.triggerOnDisplayChanged();
assertThat(mViewModel.getLiveData().getValue()).isEqualTo(mViewModel.sTestRotation);
}
public static class TestDeviceRotationViewModel extends DeviceRotationViewModel {
@Surface.Rotation static int sTestRotation = 0;
public TestDeviceRotationViewModel(@NonNull Application application) {
super(application);
}
void triggerOnDisplayChanged() {
mDisplayListener.onDisplayChanged(0);
}
@Override
protected int getRotation() {
return sTestRotation;
}
}
}

View File

@@ -1,173 +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.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import android.app.Application;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import androidx.lifecycle.LiveData;
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.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.ArrayList;
@RunWith(AndroidJUnit4.class)
public class FingerprintEnrollEnrollingViewModelTest {
private static final int TEST_USER_ID = 33;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Rule
public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
@Mock
private FingerprintManager mFingerprintManager;
private Application mApplication;
private FingerprintEnrollEnrollingViewModel mViewModel;
@Before
public void setUp() {
mApplication = ApplicationProvider.getApplicationContext();
mViewModel = new FingerprintEnrollEnrollingViewModel(
mApplication,
TEST_USER_ID,
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5)
);
}
@Test
public void testIconTouchDialog() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
assertThat(actionLiveData.getValue()).isEqualTo(null);
mViewModel.showIconTouchDialog();
assertThat(actionLiveData.getValue()).isEqualTo(
FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG);
}
@Test
public void tesBackPressedScenario() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
assertThat(actionLiveData.getValue()).isEqualTo(null);
assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
mViewModel.setOnBackPressed();
assertThat(mViewModel.getOnBackPressed()).isEqualTo(true);
mViewModel.onCancelledDueToOnBackPressed();
assertThat(mViewModel.getOnBackPressed()).isEqualTo(false);
assertThat(actionLiveData.getValue()).isEqualTo(
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED);
}
@Test
public void testSkipPressedScenario() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
assertThat(actionLiveData.getValue()).isEqualTo(null);
assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
mViewModel.setOnSkipPressed();
assertThat(mViewModel.getOnSkipPressed()).isEqualTo(true);
mViewModel.onCancelledDueToOnSkipPressed();
assertThat(mViewModel.getOnSkipPressed()).isEqualTo(false);
assertThat(actionLiveData.getValue()).isEqualTo(
FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP);
}
@Test
public void testGetFirstFingerprintSensorPropertiesInternal() {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
final FingerprintSensorPropertiesInternal prop = new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5,
new ArrayList<>() /* componentInfo */,
TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */);
props.add(prop);
doAnswer(invocation -> {
final IFingerprintAuthenticatorsRegisteredCallback callback =
invocation.getArgument(0);
callback.onAllAuthenticatorsRegistered(props);
return null;
}).when(mFingerprintManager).addAuthenticatorsRegisteredCallback(any());
mViewModel = new FingerprintEnrollEnrollingViewModel(
mApplication,
TEST_USER_ID,
new FingerprintRepository(mFingerprintManager)
);
assertThat(mViewModel.getFirstFingerprintSensorPropertiesInternal()).isEqualTo(prop);
}
@Test
public void testGetEnrollStageCount() {
final int expectedValue = 24;
doReturn(expectedValue).when(mFingerprintManager).getEnrollStageCount();
assertThat(mViewModel.getEnrollStageCount()).isEqualTo(expectedValue);
}
@Test
public void testGetEnrollStageThreshold() {
final float expectedValue0 = 0.42f;
final float expectedValue1 = 0.24f;
final float expectedValue2 = 0.33f;
final float expectedValue3 = 0.90f;
doReturn(expectedValue0).when(mFingerprintManager).getEnrollStageThreshold(0);
doReturn(expectedValue1).when(mFingerprintManager).getEnrollStageThreshold(1);
doReturn(expectedValue2).when(mFingerprintManager).getEnrollStageThreshold(2);
doReturn(expectedValue3).when(mFingerprintManager).getEnrollStageThreshold(3);
assertThat(mViewModel.getEnrollStageThreshold(2)).isEqualTo(expectedValue2);
assertThat(mViewModel.getEnrollStageThreshold(1)).isEqualTo(expectedValue1);
assertThat(mViewModel.getEnrollStageThreshold(3)).isEqualTo(expectedValue3);
assertThat(mViewModel.getEnrollStageThreshold(0)).isEqualTo(expectedValue0);
}
}

View File

@@ -1,121 +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 android.app.Application
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollErrorDialogViewModelTest {
private val application = ApplicationProvider.getApplicationContext<Application>()
private var viewModel: FingerprintEnrollErrorDialogViewModel =
FingerprintEnrollErrorDialogViewModel(application, false)
@Before
fun setUp() {
// Make sure viewModel is new for each test
viewModel = FingerprintEnrollErrorDialogViewModel(application, false)
}
@Test
fun testIsDialogNotShownDefaultFalse() {
assertThat(viewModel.isDialogShown).isFalse()
}
@Test
fun testIsSuw() {
assertThat(FingerprintEnrollErrorDialogViewModel(application, false).isSuw).isFalse()
assertThat(FingerprintEnrollErrorDialogViewModel(application, true).isSuw).isTrue()
}
@Test
fun testNewDialog() = runTest {
val newDialogs: List<Int> = mutableListOf<Int>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.newDialogFlow.toList(it)
}
}
runCurrent()
// Default values
assertThat(viewModel.isDialogShown).isFalse()
assertThat(newDialogs.size).isEqualTo(0)
val testErrorMsgId = 3456
viewModel.newDialog(testErrorMsgId)
runCurrent()
// verify after emit
assertThat(viewModel.isDialogShown).isTrue()
assertThat(newDialogs.size).isEqualTo(1)
assertThat(newDialogs[0]).isEqualTo(testErrorMsgId)
}
@Test
fun testTriggerRetry() = runTest {
val triggerRetries: List<Any> = mutableListOf<Any>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.triggerRetryFlow.toList(it)
}
}
runCurrent()
// Default values
assertThat(triggerRetries.size).isEqualTo(0)
viewModel.triggerRetry()
runCurrent()
// verify after emit
assertThat(triggerRetries.size).isEqualTo(1)
}
@Test
fun testSetResultFinish() = runTest {
val setResults: List<FingerprintErrorDialogSetResultAction> =
mutableListOf<FingerprintErrorDialogSetResultAction>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.setResultFlow.toList(it)
}
}
runCurrent()
// Default values
assertThat(setResults.size).isEqualTo(0)
viewModel.setResultAndFinish(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH)
runCurrent()
// verify after emit
assertThat(setResults.size).isEqualTo(1)
assertThat(setResults[0]).isEqualTo(FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH)
}
}

View File

@@ -1,91 +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 com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
import static com.google.common.truth.Truth.assertThat;
import android.app.Application;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.testutils.InstantTaskExecutorRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FingerprintEnrollFindSensorViewModelTest {
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
private Application mApplication;
private FingerprintEnrollFindSensorViewModel mViewModel;
@Before
public void setUp() {
mApplication = ApplicationProvider.getApplicationContext();
mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
}
@Test
public void testClickSkipButtonNotInSuw() {
mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, false);
mViewModel.onSkipButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
}
@Test
public void testClickSkipButtonInSuw() {
mViewModel = new FingerprintEnrollFindSensorViewModel(mApplication, true);
mViewModel.onSkipButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG);
}
@Test
public void testClickSkipDialogButton() {
mViewModel.onSkipDialogButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP);
}
@Test
public void testClickStartDialogButton() {
mViewModel.onStartButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isEqualTo(
FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START);
}
@Test
public void testClearActionLiveData() {
assertThat(mViewModel.getActionLiveData().getValue()).isNull();
mViewModel.onStartButtonClick();
assertThat(mViewModel.getActionLiveData().getValue()).isNotNull();
mViewModel.clearActionLiveData();
assertThat(mViewModel.getActionLiveData().getValue()).isNull();
}
}

View File

@@ -1,134 +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.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 com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
import static com.google.common.truth.Truth.assertThat;
import android.app.Application;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
import androidx.lifecycle.LiveData;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
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 FingerprintEnrollFinishViewModelTest {
private static final int USER_ID = 334;
private static final int MAX_ENROLLABLE = 5;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
@Mock private FingerprintManager mFingerprintManager;
private Application mApplication;
private EnrollmentRequest mRequest;
private FingerprintEnrollFinishViewModel mViewModel;
@Before
public void setUp() {
mApplication = ApplicationProvider.getApplicationContext();
mRequest = new EnrollmentRequest(new Intent(), mApplication, true);
mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
}
@Test
public void testCanAssumeSfps() {
mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, MAX_ENROLLABLE));
assertThat(mViewModel.canAssumeSfps()).isFalse();
mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
newFingerprintRepository(mFingerprintManager, TYPE_REAR, MAX_ENROLLABLE));
assertThat(mViewModel.canAssumeSfps()).isFalse();
mViewModel = new FingerprintEnrollFinishViewModel(mApplication, USER_ID, mRequest,
newFingerprintRepository(mFingerprintManager, TYPE_POWER_BUTTON, MAX_ENROLLABLE));
assertThat(mViewModel.canAssumeSfps()).isTrue();
}
@Test
public void testIsAnotherFingerprintEnrollable() {
setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE);
assertThat(mViewModel.isAnotherFingerprintEnrollable()).isFalse();
setupFingerprintEnrolledFingerprints(mFingerprintManager, USER_ID, MAX_ENROLLABLE - 1);
assertThat(mViewModel.isAnotherFingerprintEnrollable()).isTrue();
}
@Test
public void testGetRequest() {
assertThat(mViewModel.getRequest()).isEqualTo(mRequest);
}
@Test
public void testOnAddButtonClick() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
// Test init value
assertThat(actionLiveData.getValue()).isNull();
// Test onAddButtonClick()
mViewModel.onAddButtonClick();
assertThat(actionLiveData.getValue()).isEqualTo(
FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK);
// Clear
mViewModel.clearActionLiveData();
assertThat(actionLiveData.getValue()).isNull();
}
@Test
public void testOnNextButtonClick() {
final LiveData<Integer> actionLiveData = mViewModel.getActionLiveData();
// Test init value
assertThat(actionLiveData.getValue()).isNull();
// Test onNextButtonClick()
mViewModel.onNextButtonClick();
assertThat(actionLiveData.getValue()).isEqualTo(
FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK);
// Clear
mViewModel.clearActionLiveData();
assertThat(actionLiveData.getValue()).isNull();
}
}

View File

@@ -1,357 +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 android.app.Application
import android.content.res.Resources
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
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.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.CONTINUE_ENROLL
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.DONE_AND_FINISH
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.SKIP_OR_CANCEL
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwDeferredRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwPortalRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwSuggestedActionFlowRequest
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupSuwMaxFingerprintsEnrollable
import com.google.common.truth.Truth.assertThat
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
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollIntroViewModelTest {
@get:Rule val mockito = MockitoJUnit.rule()
@Mock private lateinit var resources: Resources
@Mock private lateinit var fingerprintManager: FingerprintManager
private var application: Application = ApplicationProvider.getApplicationContext()
private fun newFingerprintEnrollIntroViewModel(
fingerprintRepository: FingerprintRepository,
enrollmentRequest: EnrollmentRequest
) = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
enrollmentRequest,
TEST_USER_ID
)
@Before
fun setUp() {
application = ApplicationProvider.getApplicationContext()
}
@Test
fun testPageStatusFlowDefaultAndUpdate() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 1),
newAllFalseRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
// assert default values
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].hasScrollToBottom()).isFalse()
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
viewModel.updateEnrollableStatus(backgroundScope)
runCurrent()
// assert new updated value
assertThat(statusList.size).isEqualTo(2)
assertThat(statusList[1].hasScrollToBottom()).isFalse()
assertThat(statusList[1].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
fun testOnStartToUpdateEnrollableStatusOk_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
@Test
fun testOnStartToUpdateEnrollableStatusOk_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusOk(newAllFalseRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newAllFalseRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwDeferredRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwDeferredRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwPortalRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwPortalRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwSuggestedActionFlowRequest(application))
}
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(
newIsSuwSuggestedActionFlowRequest(application)
)
}
private fun TestScope.testOnStartToUpdateEnrollableStatusOk(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
private fun TestScope.testOnStartToUpdateEnrollableStatusReachMax(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 5)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
@Test
fun testIsParentalConsentRequired() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isParentalConsentRequired() calls static method inside, we can't
// mock static method
val fingerprintRepository = Mockito.mock(
FingerprintRepository::class.java
)
val viewModel = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application),
TEST_USER_ID
)
Mockito.`when`(
fingerprintRepository.isParentalConsentRequired(application)
).thenReturn(true)
assertThat(viewModel.isParentalConsentRequired).isEqualTo(true)
Mockito.`when`(
fingerprintRepository.isParentalConsentRequired(application)
).thenReturn(false)
assertThat(viewModel.isParentalConsentRequired).isEqualTo(false)
}
@Test
fun testIsBiometricUnlockDisabledByAdmin() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isDisabledByAdmin() calls static method inside, we can't mock
// static method
val fingerprintRepository = Mockito.mock(FingerprintRepository::class.java)
val viewModel = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application),
TEST_USER_ID
)
Mockito.`when`(
fingerprintRepository.isDisabledByAdmin(application, TEST_USER_ID)
).thenReturn(true)
assertThat(viewModel.isBiometricUnlockDisabledByAdmin).isEqualTo(true)
Mockito.`when`(
fingerprintRepository.isDisabledByAdmin(application, TEST_USER_ID)
).thenReturn(false)
assertThat(viewModel.isBiometricUnlockDisabledByAdmin).isEqualTo(false)
}
@Test
fun testSetHasScrolledToBottom() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(application)
)
val pageStatusList = listOfPageStatusFlow(viewModel)
viewModel.setHasScrolledToBottom(true, backgroundScope)
runCurrent()
assertThat(pageStatusList[pageStatusList.size-1].hasScrollToBottom()).isEqualTo(true)
}
@Test
fun testOnNextButtonClick_enrollNext() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_OK
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val actions = listOfActionFlow(viewModel)
// Perform click on `next`
viewModel.onNextButtonClick(backgroundScope)
runCurrent()
assertThat(actions.size).isEqualTo(1)
assertThat(actions[0]).isEqualTo(CONTINUE_ENROLL)
}
@Test
fun testOnNextButtonClick_doneAndFinish() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
val actionList = listOfActionFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
val actions = listOfActionFlow(viewModel)
// Perform click on `next`
viewModel.onNextButtonClick(backgroundScope)
runCurrent()
assertThat(actionList.size).isEqualTo(1)
assertThat(actionList[0]).isEqualTo(DONE_AND_FINISH)
}
@Test
fun testOnSkipOrCancelButtonClick() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(application)
)
val actions = listOfActionFlow(viewModel)
viewModel.onSkipOrCancelButtonClick(backgroundScope)
runCurrent()
assertThat(actions.size).isEqualTo(1)
assertThat(actions[0]).isEqualTo(SKIP_OR_CANCEL)
}
private fun TestScope.listOfActionFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroAction> =
mutableListOf<FingerprintEnrollIntroAction>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.actionFlow.toList(it)
}
}
private fun TestScope.listOfPageStatusFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroStatus> =
mutableListOf<FingerprintEnrollIntroStatus>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.pageStatusFlow.toList(it)
}
}
companion object {
private const val TEST_USER_ID = 33
}
}

View File

@@ -1,421 +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.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
import static android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR;
import static android.hardware.fingerprint.FingerprintManager.EnrollReason;
import static android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Application;
import android.content.res.Resources;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
import com.android.settings.biometrics.fingerprint.MessageDisplayController;
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
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 FingerprintEnrollProgressViewModelTest {
private static final int TEST_USER_ID = 334;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
@Mock private Application mApplication;
@Mock private Resources mResources;
@Mock private FingerprintUpdater mFingerprintUpdater;
private FingerprintEnrollProgressViewModel mViewModel;
private final TestWrapper<CancellationSignal> mCancellationSignalWrapper = new TestWrapper<>();
private final TestWrapper<EnrollmentCallback> mCallbackWrapper = new TestWrapper<>();
private int mEnrollmentMessageDisplayControllerFlagResId;
@Before
public void setUp() {
mEnrollmentMessageDisplayControllerFlagResId = ApplicationProvider.getApplicationContext()
.getResources().getIdentifier("enrollment_message_display_controller_flag", "bool",
SETTINGS_PACKAGE_NAME);
when(mApplication.getResources()).thenReturn(mResources);
// Not use MessageDisplayController by default
when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(false);
mViewModel = new FingerprintEnrollProgressViewModel(mApplication, mFingerprintUpdater,
TEST_USER_ID);
mCancellationSignalWrapper.mValue = null;
mCallbackWrapper.mValue = null;
doAnswer(invocation -> {
mCancellationSignalWrapper.mValue = invocation.getArgument(1);
mCallbackWrapper.mValue = invocation.getArgument(3);
return null;
}).when(mFingerprintUpdater).enroll(any(byte[].class), any(CancellationSignal.class),
eq(TEST_USER_ID), any(EnrollmentCallback.class), anyInt(), any());
}
@Test
public void testStartFindSensor() {
@EnrollReason final int enrollReason = ENROLL_FIND_SENSOR;
final byte[] token = new byte[] { 1, 2, 3 };
mViewModel.setToken(token);
// Start enrollment
final Object ret = mViewModel.startEnrollment(enrollReason);
assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason), any());
assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse();
}
@Test
public void testStartEnrolling() {
@EnrollReason final int enrollReason = ENROLL_ENROLL;
final byte[] token = new byte[] { 1, 2, 3 };
mViewModel.setToken(token);
// Start enrollment
final Object ret = mViewModel.startEnrollment(enrollReason);
assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason), any());
assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse();
}
@Test
public void testStartEnrollingWithMessageDisplayController() {
// Enable MessageDisplayController and mock handler for it
when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(true);
when(mApplication.getMainThreadHandler()).thenReturn(new TestHandler());
@EnrollReason final int enrollReason = ENROLL_ENROLL;
final byte[] token = new byte[] { 1, 2, 3 };
mViewModel.setToken(token);
// Start enrollment
final Object ret = mViewModel.startEnrollment(enrollReason);
assertThat(ret).isNotNull();
verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(MessageDisplayController.class), eq(enrollReason), any());
assertThat(mCallbackWrapper.mValue).isNotNull();
assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isTrue();
final EnrollmentCallback callback1 = mCallbackWrapper.mValue;
// Cancel and start again
mViewModel.cancelEnrollment();
mViewModel.startEnrollment(enrollReason);
// Shall not use the same MessageDisplayController
verify(mFingerprintUpdater, times(2)).enroll(eq(token), any(CancellationSignal.class),
eq(TEST_USER_ID), any(MessageDisplayController.class), eq(enrollReason), any());
assertThat(mCallbackWrapper.mValue).isNotNull();
assertThat(callback1).isNotEqualTo(mCallbackWrapper.mValue);
}
@Test
public void testStartEnrollmentFailBecauseOfNoToken() {
// Start enrollment
final Object ret = mViewModel.startEnrollment(ENROLL_FIND_SENSOR);
assertThat(ret).isNull();
verify(mFingerprintUpdater, never()).enroll(any(byte[].class),
any(CancellationSignal.class), anyInt(), any(EnrollmentCallback.class), anyInt(),
any());
}
@Test
public void testCancelEnrollment() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCancellationSignalWrapper.mValue).isNotNull();
// Cancel enrollment
mViewModel.cancelEnrollment();
assertThat(mCancellationSignalWrapper.mValue.isCanceled()).isTrue();
}
@Test
public void testProgressUpdate() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Test default value
final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
EnrollmentProgress progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(-1);
assertThat(progress.getRemaining()).isEqualTo(0);
// Update first progress
mCallbackWrapper.mValue.onEnrollmentProgress(25);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(25);
// Update second progress
mCallbackWrapper.mValue.onEnrollmentProgress(20);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(20);
// Update latest progress
mCallbackWrapper.mValue.onEnrollmentProgress(0);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(0);
}
@Test
public void testProgressUpdateClearHelpMessage() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
final LiveData<EnrollmentStatusMessage> helpMsgLiveData =
mViewModel.getHelpMessageLiveData();
// Update first progress
mCallbackWrapper.mValue.onEnrollmentProgress(25);
EnrollmentProgress progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(25);
// Update help message
final int testHelpMsgId = 3;
final String testHelpString = "Test Help String";
mCallbackWrapper.mValue.onEnrollmentHelp(testHelpMsgId, testHelpString);
final EnrollmentStatusMessage helpMsg = helpMsgLiveData.getValue();
assertThat(helpMsg).isNotNull();
assertThat(helpMsg.getMsgId()).isEqualTo(testHelpMsgId);
assertThat(helpMsg.getStr().toString()).isEqualTo(testHelpString);
// Update second progress
mCallbackWrapper.mValue.onEnrollmentProgress(20);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(20);
// Help message shall be set to null
assertThat(helpMsgLiveData.getValue()).isNull();
}
@Test
public void testProgressUpdateWithMessageDisplayController() {
// Enable MessageDisplayController and mock handler for it
when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(true);
when(mApplication.getMainThreadHandler()).thenReturn(new TestHandler());
mViewModel.setToken(new byte[] { 1, 2, 3 });
// Start enrollment
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Test default value
final LiveData<EnrollmentProgress> progressLiveData = mViewModel.getProgressLiveData();
EnrollmentProgress progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(-1);
assertThat(progress.getRemaining()).isEqualTo(0);
// Update first progress
mCallbackWrapper.mValue.onEnrollmentProgress(25);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(25);
// Update second progress
mCallbackWrapper.mValue.onEnrollmentProgress(20);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(20);
// Update latest progress
mCallbackWrapper.mValue.onEnrollmentProgress(0);
progress = progressLiveData.getValue();
assertThat(progress).isNotNull();
assertThat(progress.getSteps()).isEqualTo(25);
assertThat(progress.getRemaining()).isEqualTo(0);
}
@Test
public void testGetErrorMessageLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getErrorMessageLiveData();
assertThat(liveData.getValue()).isNull();
// Notify error message
final int errMsgId = 3;
final String errMsg = "test error message";
mCallbackWrapper.mValue.onEnrollmentError(errMsgId, errMsg);
final EnrollmentStatusMessage value = liveData.getValue();
assertThat(value).isNotNull();
assertThat(value.getMsgId()).isEqualTo(errMsgId);
assertThat(value.getStr().toString()).isEqualTo(errMsg);
}
@Test
public void testGetHelpMessageLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
final LiveData<EnrollmentStatusMessage> liveData = mViewModel.getHelpMessageLiveData();
assertThat(liveData.getValue()).isNull();
// Notify help message
final int errMsgId = 3;
final String errMsg = "test error message";
mCallbackWrapper.mValue.onEnrollmentHelp(errMsgId, errMsg);
final EnrollmentStatusMessage value = liveData.getValue();
assertThat(value).isNotNull();
assertThat(value.getMsgId()).isEqualTo(errMsgId);
assertThat(value.getStr().toString()).isEqualTo(errMsg);
}
@Test
public void testGetAcquireLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
final LiveData<Boolean> liveData = mViewModel.getAcquireLiveData();
assertThat(liveData.getValue()).isNull();
// Notify acquire message
mCallbackWrapper.mValue.onAcquired(true);
assertThat(liveData.getValue()).isTrue();
}
@Test
public void testGetPointerDownLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
final LiveData<Integer> liveData = mViewModel.getPointerDownLiveData();
assertThat(liveData.getValue()).isNull();
// Notify acquire message
final int value = 33;
mCallbackWrapper.mValue.onUdfpsPointerDown(value);
assertThat(liveData.getValue()).isEqualTo(value);
}
@Test
public void testGetPointerUpLiveData() {
// Start enrollment
mViewModel.setToken(new byte[] { 1, 2, 3 });
final Object ret = mViewModel.startEnrollment(ENROLL_ENROLL);
assertThat(ret).isNotNull();
assertThat(mCallbackWrapper.mValue).isNotNull();
// Check default value
final LiveData<Integer> liveData = mViewModel.getPointerUpLiveData();
assertThat(liveData.getValue()).isNull();
// Notify acquire message
final int value = 44;
mCallbackWrapper.mValue.onUdfpsPointerUp(value);
assertThat(liveData.getValue()).isEqualTo(value);
}
private static class TestWrapper<T> {
T mValue;
}
private static class TestHandler extends Handler {
TestHandler() {
super(Looper.getMainLooper());
}
@Override
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
msg.getCallback().run();
return true;
}
}
}

View File

@@ -1,322 +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 android.app.Application
import android.content.Intent
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorProperties
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.google.common.truth.Truth.assertThat
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.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollmentViewModelTest {
@get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
private val application: Application
get() = ApplicationProvider.getApplicationContext()
@Mock
private lateinit var fingerprintManager: FingerprintManager
private lateinit var fingerprintRepository: FingerprintRepository
private lateinit var viewModel: FingerprintEnrollmentViewModel
@Before
fun setUp() {
fingerprintRepository = newFingerprintRepository(
fingerprintManager,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
5
)
viewModel = FingerprintEnrollmentViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application)
)
}
@Test
fun testGetRequest() {
assertThat(viewModel.request).isNotNull()
}
@Test
fun testIsWaitingActivityResultDefaultFalse() {
assertThat(viewModel.isWaitingActivityResult.value).isFalse()
}
@Test
fun testOverrideActivityResult_shallKeepNullIntent_woChallengeExtra() {
val retResult = viewModel.getOverrideActivityResult(
ActivityResult(22, null), null
)
assertThat(retResult).isNotNull()
assertThat(retResult.data).isNull()
}
@Test
fun testOverrideActivityResult_shallKeepNullIntent_noIntent_woChallengeExtra() {
val intent = Intent()
val retResult = viewModel.getOverrideActivityResult(
ActivityResult(33, intent), null
)
assertThat(retResult).isNotNull()
assertThat(retResult.data).isEqualTo(intent)
}
@Test
fun testOverrideActivityResult_shallKeepNull_woAdded_woIntent_withChallenge() {
val extra = Bundle()
extra.putString("test1", "test123")
val retResult = viewModel.getOverrideActivityResult(
ActivityResult(33, null), extra
)
assertThat(retResult).isNotNull()
assertThat(retResult.data).isNull()
}
@Test
fun testOverrideActivityResult_shallCreateNew_woIntent_withChallenge() {
val key1 = "test1"
val key2 = "test2"
val extra = Bundle().apply {
putString(key1, "test123")
putInt(key2, 9999)
}
viewModel.isNewFingerprintAdded = true
val retResult = viewModel.getOverrideActivityResult(
ActivityResult(33, null), extra
)
assertThat(retResult).isNotNull()
val retIntent = retResult.data
assertThat(retIntent).isNotNull()
val retExtra = retIntent!!.extras
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
fun testOverrideActivityResult_shallNotMerge_nonAdded_woIntent_withChallenge() {
val extra = Bundle().apply {
putString("test2", "test123")
}
val key2 = "test2"
val intent = Intent().apply {
putExtra(key2, 3456L)
}
val retResult = viewModel.getOverrideActivityResult(ActivityResult(33, intent), extra)
assertThat(retResult).isNotNull()
val retIntent = retResult.data
assertThat(retIntent).isNotNull()
val retExtra = retIntent!!.extras
assertThat(retExtra).isNotNull()
assertThat(retExtra!!.size).isEqualTo(intent.extras!!.size)
assertThat(retExtra.getString(key2)).isEqualTo(intent.extras!!.getString(key2))
}
@Test
fun testOverrideActivityResult_shallMerge_added_woIntent_withChallenge() {
val key1 = "test1"
val key2 = "test2"
val extra = Bundle().apply {
putString(key1, "test123")
putInt(key2, 9999)
}
val key3 = "test3"
val intent = Intent().apply {
putExtra(key3, 3456L)
}
viewModel.isNewFingerprintAdded = true
val retResult = viewModel.getOverrideActivityResult(ActivityResult(33, intent), extra)
assertThat(retResult).isNotNull()
val retIntent = retResult.data
assertThat(retIntent).isNotNull()
val retExtra = retIntent!!.extras
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
fun testIsMaxEnrolledReached() {
val uid = 100
fingerprintRepository = newFingerprintRepository(
fingerprintManager,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
3
)
viewModel = FingerprintEnrollmentViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application)
)
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 0)
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 1)
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 2)
assertThat(viewModel.isMaxEnrolledReached(uid)).isFalse()
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 3)
assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
setupFingerprintEnrolledFingerprints(fingerprintManager, uid, 4)
assertThat(viewModel.isMaxEnrolledReached(uid)).isTrue()
}
@Test
fun testSetResultFlow_defaultEmpty() = runTest {
val activityResults = listOfSetResultFlow()
runCurrent()
assertThat(activityResults.size).isEqualTo(0)
}
@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)
}
@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)
}
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsActivityFinishing() = runTest {
val activityResults = listOfSetResultFlow()
viewModel.checkFinishActivityDuringOnPause(
isActivityFinishing = true,
isChangingConfigurations = false,
scope = this
)
runCurrent()
assertThat(activityResults.size).isEqualTo(0)
}
@Test
fun testCheckFinishActivityDuringOnPause_doNothingIfIsChangingConfigurations() = runTest {
val activityResults = listOfSetResultFlow()
viewModel.checkFinishActivityDuringOnPause(
isActivityFinishing = false,
isChangingConfigurations = true,
scope = this
)
runCurrent()
assertThat(activityResults.size).isEqualTo(0)
}
@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)
}
private fun TestScope.listOfSetResultFlow(): List<ActivityResult> =
mutableListOf<ActivityResult>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.setResultFlow.toList(it)
}
}
}

View File

@@ -1,110 +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.utils
import android.content.Context
import android.content.Intent
import android.text.TextUtils
import com.android.settings.biometrics.BiometricEnrollBase
import com.android.settings.biometrics2.ui.model.EnrollmentRequest
import com.google.android.setupcompat.util.WizardManagerHelper
object EnrollmentRequestUtils {
@JvmStatic
fun newAllFalseRequest(context: Context): EnrollmentRequest {
return newRequest(
context = context,
isSuw = false,
isSuwDeferred = false,
isSuwPortal = false,
isSuwSuggestedActionFlow = false,
isSuwFirstRun = false,
isFromSettingsSummery = false)
}
@JvmStatic
fun newIsSuwRequest(context: Context): EnrollmentRequest {
return newRequest(
context = context,
isSuw = true,
isSuwDeferred = false,
isSuwPortal = false,
isSuwSuggestedActionFlow = false,
isSuwFirstRun = false,
isFromSettingsSummery = false)
}
@JvmStatic
fun newIsSuwDeferredRequest(context: Context): EnrollmentRequest {
return newRequest(
context = context,
isSuw = true,
isSuwDeferred = true,
isSuwPortal = false,
isSuwSuggestedActionFlow = false,
isSuwFirstRun = false,
isFromSettingsSummery = false, null)
}
@JvmStatic
fun newIsSuwPortalRequest(context: Context): EnrollmentRequest {
return newRequest(
context = context,
isSuw = true,
isSuwDeferred = false,
isSuwPortal = true,
isSuwSuggestedActionFlow = false,
isSuwFirstRun = false,
isFromSettingsSummery = false)
}
@JvmStatic
fun newIsSuwSuggestedActionFlowRequest(
context: Context
): EnrollmentRequest {
return newRequest(
context = context,
isSuw = true,
isSuwDeferred = false,
isSuwPortal = false,
isSuwSuggestedActionFlow = true,
isSuwFirstRun = false,
isFromSettingsSummery = false)
}
fun newRequest(
context: Context,
isSuw: Boolean,
isSuwDeferred: Boolean,
isSuwPortal: Boolean,
isSuwSuggestedActionFlow: Boolean,
isSuwFirstRun: Boolean,
isFromSettingsSummery: Boolean,
theme: String? = null
): EnrollmentRequest {
val i = Intent()
i.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, isSuw)
i.putExtra(WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP, isSuwDeferred)
i.putExtra(WizardManagerHelper.EXTRA_IS_PORTAL_SETUP, isSuwPortal)
i.putExtra(WizardManagerHelper.EXTRA_IS_SUW_SUGGESTED_ACTION_FLOW, isSuwSuggestedActionFlow)
i.putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, isSuwFirstRun)
i.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, isFromSettingsSummery)
if (!TextUtils.isEmpty(theme)) {
i.putExtra(WizardManagerHelper.EXTRA_THEME, theme)
}
return EnrollmentRequest(i, context, true)
}
}

View File

@@ -1,81 +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.utils;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
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 android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import androidx.annotation.NonNull;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
import java.util.ArrayList;
public class FingerprintRepositoryUtils {
public static void setupSuwMaxFingerprintsEnrollable(
@NonNull Context context,
@NonNull Resources mockedResources,
int numOfFp) {
final int resId = context.getResources().getIdentifier("suw_max_fingerprints_enrollable",
"integer", context.getPackageName());
when(mockedResources.getInteger(resId)).thenReturn(numOfFp);
}
public static FingerprintRepository newFingerprintRepository(
@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 */));
doAnswer(invocation -> {
final IFingerprintAuthenticatorsRegisteredCallback callback =
invocation.getArgument(0);
callback.onAllAuthenticatorsRegistered(props);
return null;
}).when(mockedFingerprintManager).addAuthenticatorsRegisteredCallback(any());
return new FingerprintRepository(mockedFingerprintManager);
}
public static void setupFingerprintEnrolledFingerprints(
@NonNull FingerprintManager mockedFingerprintManager,
int userId,
int enrolledFingerprints) {
final ArrayList<Fingerprint> ret = new ArrayList<>();
for (int i = 0; i < enrolledFingerprints; ++i) {
ret.add(new Fingerprint("name", 0, 0, 0L));
}
when(mockedFingerprintManager.getEnrolledFingerprints(userId)).thenReturn(ret);
}
}

View File

@@ -0,0 +1,409 @@
/*
* Copyright (C) 2024 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.connecteddevice.display;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.PREVIOUSLY_SHOWN_LIST_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.DISPLAYS_LIST_PREFERENCE_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_RESOLUTION_TITLE_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_ROTATION_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_ROTATION_TITLE_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SETTINGS_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_USE_PREFERENCE_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_USE_TITLE_RESOURCE;
import static com.android.settingslib.widget.FooterPreference.KEY_FOOTER;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.DisplayPreference;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.MainSwitchPreference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
/** Unit tests for {@link ExternalDisplayPreferenceFragment}. */
@RunWith(AndroidJUnit4.class)
public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBase {
@Nullable
private ExternalDisplayPreferenceFragment mFragment;
private int mPreferenceIdFromResource;
private int mDisplayIdArg = INVALID_DISPLAY;
private int mResolutionSelectorDisplayId = INVALID_DISPLAY;
@Mock
private MetricsLogger mMockedMetricsLogger;
@Test
@UiThreadTest
public void testCreateAndStart() {
initFragment();
assertThat(mPreferenceIdFromResource).isEqualTo(EXTERNAL_DISPLAY_SETTINGS_RESOURCE);
}
@Test
@UiThreadTest
public void testShowDisplayList() {
var fragment = initFragment();
var outState = new Bundle();
fragment.onSaveInstanceStateCallback(outState);
assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isFalse();
assertThat(mHandler.getPendingMessages().size()).isEqualTo(1);
PreferenceCategory pref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(pref).isNull();
verify(mMockedInjector, never()).getAllDisplays();
mHandler.flush();
assertThat(mHandler.getPendingMessages().size()).isEqualTo(0);
verify(mMockedInjector).getAllDisplays();
pref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(pref).isNotNull();
assertThat(pref.getPreferenceCount()).isEqualTo(2);
fragment.onSaveInstanceStateCallback(outState);
assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isTrue();
}
@Test
@UiThreadTest
public void testLaunchDisplaySettingFromList() {
initFragment();
mHandler.flush();
PreferenceCategory pref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(pref).isNotNull();
DisplayPreference display1Pref = (DisplayPreference) pref.getPreference(0);
DisplayPreference display2Pref = (DisplayPreference) pref.getPreference(1);
assertThat(display1Pref.getKey()).isEqualTo("display_id_" + 1);
assertThat("" + display1Pref.getTitle()).isEqualTo("HDMI");
assertThat("" + display1Pref.getSummary()).isEqualTo("1920 x 1080");
display1Pref.onPreferenceClick(display1Pref);
assertThat(mDisplayIdArg).isEqualTo(1);
verify(mMockedMetricsLogger).writePreferenceClickMetric(display1Pref);
assertThat(display2Pref.getKey()).isEqualTo("display_id_" + 2);
assertThat("" + display2Pref.getTitle()).isEqualTo("Overlay #1");
assertThat("" + display2Pref.getSummary()).isEqualTo("1240 x 780");
display2Pref.onPreferenceClick(display2Pref);
assertThat(mDisplayIdArg).isEqualTo(2);
verify(mMockedMetricsLogger).writePreferenceClickMetric(display2Pref);
}
@Test
@UiThreadTest
public void testShowDisplayListForOnlyOneDisplay_PreviouslyShownList() {
var fragment = initFragment();
// Previously shown list of displays
fragment.onActivityCreatedCallback(createBundleForPreviouslyShownList());
// Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays();
mHandler.flush();
PreferenceCategory pref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(pref).isNotNull();
assertThat(pref.getPreferenceCount()).isEqualTo(1);
}
@Test
@UiThreadTest
public void testShowEnabledDisplay_OnlyOneDisplayAvailable() {
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
// Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays();
// Init
initFragment();
mHandler.flush();
PreferenceCategory list = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(list).isNull();
var pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY);
assertThat(pref).isNotNull();
pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_ROTATION_KEY);
assertThat(pref).isNotNull();
var footerPref = (FooterPreference) mPreferenceScreen.findPreference(KEY_FOOTER);
assertThat(footerPref).isNotNull();
verify(footerPref).setTitle(EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE);
}
@Test
@UiThreadTest
public void testShowOneEnabledDisplay_FewAvailable() {
mDisplayIdArg = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
initFragment();
verify(mMockedInjector, never()).getDisplay(anyInt());
mHandler.flush();
verify(mMockedInjector).getDisplay(mDisplayIdArg);
var pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY);
assertThat(pref).isNotNull();
pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_ROTATION_KEY);
assertThat(pref).isNotNull();
var footerPref = (FooterPreference) mPreferenceScreen.findPreference(KEY_FOOTER);
assertThat(footerPref).isNotNull();
verify(footerPref).setTitle(EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE);
}
@Test
@UiThreadTest
public void testShowDisabledDisplay() {
mDisplayIdArg = 1;
initFragment();
verify(mMockedInjector, never()).getDisplay(anyInt());
mHandler.flush();
verify(mMockedInjector).getDisplay(mDisplayIdArg);
var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference(
EXTERNAL_DISPLAY_USE_PREFERENCE_KEY);
assertThat(mainPref).isNotNull();
assertThat("" + mainPref.getTitle()).isEqualTo(
getText(EXTERNAL_DISPLAY_USE_TITLE_RESOURCE));
assertThat(mainPref.isChecked()).isFalse();
assertThat(mainPref.isEnabled()).isTrue();
assertThat(mainPref.getOnPreferenceChangeListener()).isNotNull();
var pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY);
assertThat(pref).isNull();
pref = mPreferenceScreen.findPreference(EXTERNAL_DISPLAY_ROTATION_KEY);
assertThat(pref).isNull();
var footerPref = (FooterPreference) mPreferenceScreen.findPreference(KEY_FOOTER);
assertThat(footerPref).isNull();
}
@Test
@UiThreadTest
public void testNoDisplays() {
doReturn(new Display[0]).when(mMockedInjector).getAllDisplays();
initFragment();
mHandler.flush();
var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference(
EXTERNAL_DISPLAY_USE_PREFERENCE_KEY);
assertThat(mainPref).isNotNull();
assertThat("" + mainPref.getTitle()).isEqualTo(
getText(EXTERNAL_DISPLAY_USE_TITLE_RESOURCE));
assertThat(mainPref.isChecked()).isFalse();
assertThat(mainPref.isEnabled()).isFalse();
assertThat(mainPref.getOnPreferenceChangeListener()).isNull();
var footerPref = (FooterPreference) mPreferenceScreen.findPreference(KEY_FOOTER);
assertThat(footerPref).isNotNull();
verify(footerPref).setTitle(EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE);
}
@Test
@UiThreadTest
public void testDisplayRotationPreference() {
mDisplayIdArg = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
var fragment = initFragment();
mHandler.flush();
var pref = fragment.getRotationPreference(mContext);
assertThat(pref.getKey()).isEqualTo(EXTERNAL_DISPLAY_ROTATION_KEY);
assertThat("" + pref.getTitle()).isEqualTo(
getText(EXTERNAL_DISPLAY_ROTATION_TITLE_RESOURCE));
assertThat(pref.getEntries().length).isEqualTo(4);
assertThat(pref.getEntryValues().length).isEqualTo(4);
assertThat(pref.getEntryValues()[0].toString()).isEqualTo("0");
assertThat(pref.getEntryValues()[1].toString()).isEqualTo("1");
assertThat(pref.getEntryValues()[2].toString()).isEqualTo("2");
assertThat(pref.getEntryValues()[3].toString()).isEqualTo("3");
assertThat(pref.getEntries()[0].length()).isGreaterThan(0);
assertThat(pref.getEntries()[1].length()).isGreaterThan(0);
assertThat("" + pref.getSummary()).isEqualTo(pref.getEntries()[0].toString());
assertThat(pref.getValue()).isEqualTo("0");
assertThat(pref.getOnPreferenceChangeListener()).isNotNull();
assertThat(pref.isEnabled()).isTrue();
var rotation = 1;
doReturn(true).when(mMockedInjector).freezeDisplayRotation(mDisplayIdArg, rotation);
assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, rotation + ""))
.isTrue();
verify(mMockedInjector).freezeDisplayRotation(mDisplayIdArg, rotation);
assertThat(pref.getValue()).isEqualTo(rotation + "");
verify(mMockedMetricsLogger).writePreferenceClickMetric(pref);
}
@Test
@UiThreadTest
public void testDisplayResolutionPreference() {
mDisplayIdArg = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
var fragment = initFragment();
mHandler.flush();
var pref = fragment.getResolutionPreference(mContext);
assertThat(pref.getKey()).isEqualTo(EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY);
assertThat("" + pref.getTitle()).isEqualTo(
getText(EXTERNAL_DISPLAY_RESOLUTION_TITLE_RESOURCE));
assertThat("" + pref.getSummary()).isEqualTo("1920 x 1080");
assertThat(pref.isEnabled()).isTrue();
assertThat(pref.getOnPreferenceClickListener()).isNotNull();
assertThat(pref.getOnPreferenceClickListener().onPreferenceClick(pref)).isTrue();
assertThat(mResolutionSelectorDisplayId).isEqualTo(mDisplayIdArg);
verify(mMockedMetricsLogger).writePreferenceClickMetric(pref);
}
@Test
@UiThreadTest
public void testUseDisplayPreference_EnabledDisplay() {
mDisplayIdArg = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
doReturn(true).when(mMockedInjector).enableConnectedDisplay(mDisplayIdArg);
doReturn(true).when(mMockedInjector).disableConnectedDisplay(mDisplayIdArg);
var fragment = initFragment();
mHandler.flush();
var pref = fragment.getUseDisplayPreference(mContext);
assertThat(pref.getKey()).isEqualTo(EXTERNAL_DISPLAY_USE_PREFERENCE_KEY);
assertThat("" + pref.getTitle()).isEqualTo(getText(EXTERNAL_DISPLAY_USE_TITLE_RESOURCE));
assertThat(pref.isEnabled()).isTrue();
assertThat(pref.isChecked()).isTrue();
assertThat(pref.getOnPreferenceChangeListener()).isNotNull();
assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, false)).isTrue();
verify(mMockedInjector).disableConnectedDisplay(mDisplayIdArg);
assertThat(pref.isChecked()).isFalse();
assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, true)).isTrue();
verify(mMockedInjector).enableConnectedDisplay(mDisplayIdArg);
assertThat(pref.isChecked()).isTrue();
verify(mMockedMetricsLogger, times(2)).writePreferenceClickMetric(pref);
}
@NonNull
private ExternalDisplayPreferenceFragment initFragment() {
if (mFragment != null) {
return mFragment;
}
mFragment = new TestableExternalDisplayPreferenceFragment();
mFragment.onCreateCallback(null);
mFragment.onActivityCreatedCallback(null);
mFragment.onStartCallback();
return mFragment;
}
@NonNull
private Bundle createBundleForPreviouslyShownList() {
var state = new Bundle();
state.putBoolean(PREVIOUSLY_SHOWN_LIST_KEY, true);
return state;
}
@NonNull
private String getText(int id) {
return mContext.getResources().getText(id).toString();
}
private class TestableExternalDisplayPreferenceFragment extends
ExternalDisplayPreferenceFragment {
private final View mMockedRootView;
private final TextView mEmptyView;
private final Activity mMockedActivity;
private final FooterPreference mMockedFooterPreference;
private final MetricsLogger mLogger;
TestableExternalDisplayPreferenceFragment() {
super(mMockedInjector);
mMockedActivity = mock(Activity.class);
mMockedRootView = mock(View.class);
mMockedFooterPreference = mock(FooterPreference.class);
doReturn(KEY_FOOTER).when(mMockedFooterPreference).getKey();
mEmptyView = new TextView(mContext);
doReturn(mEmptyView).when(mMockedRootView).findViewById(android.R.id.empty);
mLogger = mMockedMetricsLogger;
}
@Override
public PreferenceScreen getPreferenceScreen() {
return mPreferenceScreen;
}
@Override
protected Activity getCurrentActivity() {
return mMockedActivity;
}
@Override
public View getView() {
return mMockedRootView;
}
@Override
public void setEmptyView(View view) {
assertThat(view).isEqualTo(mEmptyView);
}
@Override
public View getEmptyView() {
return mEmptyView;
}
@Override
public void addPreferencesFromResource(int resource) {
mPreferenceIdFromResource = resource;
}
@Override
@NonNull
FooterPreference getFooterPreference(@NonNull Context context) {
return mMockedFooterPreference;
}
@Override
protected int getDisplayIdArg() {
return mDisplayIdArg;
}
@Override
protected void launchResolutionSelector(@NonNull Context context, int displayId) {
mResolutionSelectorDisplayId = displayId;
}
@Override
protected void launchDisplaySettings(final int displayId) {
mDisplayIdArg = displayId;
}
@Override
protected void writePreferenceClickMetric(Preference preference) {
mLogger.writePreferenceClickMetric(preference);
}
}
/**
* Interface allowing to mock and spy on log events.
*/
public interface MetricsLogger {
/**
* On preference click metric
*/
void writePreferenceClickMetric(Preference preference);
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2024 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.connecteddevice.display;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY;
import static com.android.settings.flags.Flags.FLAG_ROTATION_CONNECTED_DISPLAY_SETTING;
import static com.android.settings.flags.Flags.FLAG_RESOLUTION_AND_ENABLE_CONNECTED_DISPLAY_SETTING;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.IDisplayManager;
import android.os.RemoteException;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.testutils.TestHandler;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
import com.android.settings.flags.FakeFeatureFlagsImpl;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class ExternalDisplayTestBase {
@Mock
ExternalDisplaySettingsConfiguration.Injector mMockedInjector;
@Mock
IDisplayManager mMockedIDisplayManager;
Resources mResources;
DisplayManagerGlobal mDisplayManagerGlobal;
FakeFeatureFlagsImpl mFlags = new FakeFeatureFlagsImpl();
Context mContext;
DisplayListener mListener;
TestHandler mHandler = new TestHandler(null);
PreferenceManager mPreferenceManager;
PreferenceScreen mPreferenceScreen;
Display[] mDisplays;
/**
* Setup.
*/
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
doReturn(mResources).when(mContext).getResources();
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
doReturn(0).when(mMockedIDisplayManager).getPreferredWideGamutColorSpaceId();
mDisplayManagerGlobal = new DisplayManagerGlobal(mMockedIDisplayManager);
mFlags.setFlag(FLAG_ROTATION_CONNECTED_DISPLAY_SETTING, true);
mFlags.setFlag(FLAG_RESOLUTION_AND_ENABLE_CONNECTED_DISPLAY_SETTING, true);
mDisplays = new Display[] {
createDefaultDisplay(), createExternalDisplay(), createOverlayDisplay()};
doReturn(mDisplays).when(mMockedInjector).getAllDisplays();
doReturn(mDisplays).when(mMockedInjector).getEnabledDisplays();
for (var display : mDisplays) {
doReturn(display).when(mMockedInjector).getDisplay(display.getDisplayId());
}
doReturn(mFlags).when(mMockedInjector).getFlags();
doReturn(mHandler).when(mMockedInjector).getHandler();
doReturn("").when(mMockedInjector).getSystemProperty(
VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY);
doReturn(true).when(mMockedInjector).isModeLimitForExternalDisplayEnabled();
doAnswer((arg) -> {
mListener = arg.getArgument(0);
return null;
}).when(mMockedInjector).registerDisplayListener(any());
doReturn(0).when(mMockedInjector).getDisplayUserRotation(anyInt());
doReturn(mContext).when(mMockedInjector).getContext();
}
Display createDefaultDisplay() throws RemoteException {
int displayId = 0;
var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId;
displayInfo.name = "Built-in";
displayInfo.type = Display.TYPE_INTERNAL;
displayInfo.supportedModes = new Display.Mode[]{
new Display.Mode(0, 2048, 1024, 60, 60, new float[0],
new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
}
Display createExternalDisplay() throws RemoteException {
int displayId = 1;
var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId;
displayInfo.name = "HDMI";
displayInfo.type = Display.TYPE_EXTERNAL;
displayInfo.supportedModes = new Display.Mode[]{
new Display.Mode(0, 1920, 1080, 60, 60, new float[0], new int[0]),
new Display.Mode(1, 800, 600, 60, 60, new float[0], new int[0]),
new Display.Mode(2, 320, 240, 70, 70, new float[0], new int[0]),
new Display.Mode(3, 640, 480, 60, 60, new float[0], new int[0]),
new Display.Mode(4, 640, 480, 50, 60, new float[0], new int[0]),
new Display.Mode(5, 2048, 1024, 60, 60, new float[0], new int[0]),
new Display.Mode(6, 720, 480, 60, 60, new float[0], new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
}
Display createOverlayDisplay() throws RemoteException {
int displayId = 2;
var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId;
displayInfo.name = "Overlay #1";
displayInfo.type = Display.TYPE_OVERLAY;
displayInfo.supportedModes = new Display.Mode[]{
new Display.Mode(0, 1240, 780, 60, 60, new float[0],
new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
}
Display createDisplay(DisplayInfo displayInfo) {
return new Display(mDisplayManagerGlobal, displayInfo.displayId, displayInfo,
(DisplayAdjustments) null);
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2024 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.connecteddevice.display;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.view.Display;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
/** Unit tests for {@link ExternalDisplayUpdater}. */
@RunWith(AndroidJUnit4.class)
public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase {
private ExternalDisplayUpdater mUpdater;
@Mock
private DevicePreferenceCallback mMockedCallback;
@Mock
private Drawable mMockedDrawable;
private RestrictedPreference mPreferenceAdded;
private RestrictedPreference mPreferenceRemoved;
@Before
public void setUp() throws RemoteException {
super.setUp();
mUpdater = new TestableExternalDisplayUpdater(mMockedCallback, /*metricsCategory=*/ 0);
}
@Test
public void testPreferenceAdded() {
doAnswer((v) -> {
mPreferenceAdded = v.getArgument(0);
return null;
}).when(mMockedCallback).onDeviceAdded(any());
mUpdater.initPreference(mContext, mMockedInjector);
mUpdater.registerCallback();
mHandler.flush();
assertThat(mPreferenceAdded).isNotNull();
var summary = mPreferenceAdded.getSummary();
assertThat(summary).isNotNull();
assertThat(summary.length()).isGreaterThan(0);
var title = mPreferenceAdded.getTitle();
assertThat(title).isNotNull();
assertThat(title.length()).isGreaterThan(0);
}
@Test
public void testPreferenceRemoved() {
doAnswer((v) -> {
mPreferenceAdded = v.getArgument(0);
return null;
}).when(mMockedCallback).onDeviceAdded(any());
doAnswer((v) -> {
mPreferenceRemoved = v.getArgument(0);
return null;
}).when(mMockedCallback).onDeviceRemoved(any());
mUpdater.initPreference(mContext, mMockedInjector);
mUpdater.registerCallback();
mHandler.flush();
assertThat(mPreferenceAdded).isNotNull();
assertThat(mPreferenceRemoved).isNull();
// Remove display
doReturn(new Display[0]).when(mMockedInjector).getAllDisplays();
doReturn(new Display[0]).when(mMockedInjector).getEnabledDisplays();
mListener.onDisplayRemoved(1);
mHandler.flush();
assertThat(mPreferenceRemoved).isEqualTo(mPreferenceAdded);
}
class TestableExternalDisplayUpdater extends ExternalDisplayUpdater {
TestableExternalDisplayUpdater(
DevicePreferenceCallback callback,
int metricsCategory) {
super(callback, metricsCategory);
}
@Override
@Nullable
protected RestrictedLockUtils.EnforcedAdmin checkIfUsbDataSignalingIsDisabled(
Context context) {
// if null is returned - usb signalling is enabled
return null;
}
@Override
@Nullable
protected Drawable getDrawable(Context context) {
return mMockedDrawable;
}
}
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright (C) 2024 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.connecteddevice.display;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.settings.connecteddevice.display.ResolutionPreferenceFragment.DISPLAY_MODE_LIMIT_OVERRIDE_PROP;
import static com.android.settings.connecteddevice.display.ResolutionPreferenceFragment.EXTERNAL_DISPLAY_RESOLUTION_SETTINGS_RESOURCE;
import static com.android.settings.connecteddevice.display.ResolutionPreferenceFragment.MORE_OPTIONS_KEY;
import static com.android.settings.connecteddevice.display.ResolutionPreferenceFragment.TOP_OPTIONS_KEY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Resources;
import android.util.Pair;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
/** Unit tests for {@link ResolutionPreferenceFragment}. */
@RunWith(AndroidJUnit4.class)
public class ResolutionPreferenceFragmentTest extends ExternalDisplayTestBase {
@Nullable
private ResolutionPreferenceFragment mFragment;
private int mPreferenceIdFromResource;
private int mDisplayIdArg = INVALID_DISPLAY;
@Mock
private MetricsLogger mMockedMetricsLogger;
@Test
@UiThreadTest
public void testCreateAndStart() {
initFragment();
mHandler.flush();
assertThat(mPreferenceIdFromResource).isEqualTo(
EXTERNAL_DISPLAY_RESOLUTION_SETTINGS_RESOURCE);
var pref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY);
assertThat(pref).isNull();
pref = mPreferenceScreen.findPreference(MORE_OPTIONS_KEY);
assertThat(pref).isNull();
}
@Test
@UiThreadTest
public void testCreateAndStartDefaultDisplayNotAllowed() {
mDisplayIdArg = 0;
initFragment();
mHandler.flush();
var pref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY);
assertThat(pref).isNull();
pref = mPreferenceScreen.findPreference(MORE_OPTIONS_KEY);
assertThat(pref).isNull();
}
@Test
@UiThreadTest
public void testModePreferences_modeLimitFlagIsOn_noOverride() {
doReturn(true).when(mMockedInjector).isModeLimitForExternalDisplayEnabled();
doReturn(null).when(mMockedInjector).getSystemProperty(
DISPLAY_MODE_LIMIT_OVERRIDE_PROP);
var topAndMorePref = runTestModePreferences();
PreferenceCategory topPref = topAndMorePref.first, morePref = topAndMorePref.second;
assertThat(topPref.getPreferenceCount()).isEqualTo(3);
assertThat(morePref.getPreferenceCount()).isEqualTo(1);
}
@Test
@UiThreadTest
public void testModePreferences_noModeLimitFlag_overrideIsTrue() {
doReturn(false).when(mMockedInjector).isModeLimitForExternalDisplayEnabled();
doReturn("true").when(mMockedInjector).getSystemProperty(
DISPLAY_MODE_LIMIT_OVERRIDE_PROP);
var topAndMorePref = runTestModePreferences();
PreferenceCategory topPref = topAndMorePref.first, morePref = topAndMorePref.second;
assertThat(topPref.getPreferenceCount()).isEqualTo(3);
assertThat(morePref.getPreferenceCount()).isEqualTo(1);
}
@Test
@UiThreadTest
public void testModePreferences_noModeLimitFlag_noOverride() {
doReturn(false).when(mMockedInjector).isModeLimitForExternalDisplayEnabled();
doReturn(null).when(mMockedInjector).getSystemProperty(
DISPLAY_MODE_LIMIT_OVERRIDE_PROP);
var topAndMorePref = runTestModePreferences();
PreferenceCategory topPref = topAndMorePref.first, morePref = topAndMorePref.second;
assertThat(topPref.getPreferenceCount()).isEqualTo(3);
assertThat(morePref.getPreferenceCount()).isEqualTo(2);
}
@Test
@UiThreadTest
public void testModePreferences_modeLimitFlagIsOn_butOverrideIsFalse() {
doReturn(true).when(mMockedInjector).isModeLimitForExternalDisplayEnabled();
doReturn("false").when(mMockedInjector).getSystemProperty(
DISPLAY_MODE_LIMIT_OVERRIDE_PROP);
var topAndMorePref = runTestModePreferences();
PreferenceCategory topPref = topAndMorePref.first, morePref = topAndMorePref.second;
assertThat(topPref.getPreferenceCount()).isEqualTo(3);
assertThat(morePref.getPreferenceCount()).isEqualTo(2);
}
@Test
@UiThreadTest
public void testModeChange() {
mDisplayIdArg = 1;
initFragment();
mHandler.flush();
PreferenceCategory topPref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY);
assertThat(topPref).isNotNull();
var modePref = (SelectorWithWidgetPreference) topPref.getPreference(1);
modePref.onClick();
var mode = mDisplays[mDisplayIdArg].getSupportedModes()[1];
verify(mMockedInjector).setUserPreferredDisplayMode(mDisplayIdArg, mode);
}
private Pair<PreferenceCategory, PreferenceCategory> runTestModePreferences() {
mDisplayIdArg = 1;
initFragment();
mHandler.flush();
PreferenceCategory topPref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY);
assertThat(topPref).isNotNull();
PreferenceCategory morePref = mPreferenceScreen.findPreference(MORE_OPTIONS_KEY);
assertThat(morePref).isNotNull();
return new Pair<>(topPref, morePref);
}
private void initFragment() {
if (mFragment != null) {
return;
}
mFragment = new TestableResolutionPreferenceFragment();
mFragment.onCreateCallback(null);
mFragment.onActivityCreatedCallback(null);
mFragment.onStartCallback();
}
private class TestableResolutionPreferenceFragment extends ResolutionPreferenceFragment {
private final View mMockedRootView;
private final TextView mEmptyView;
private final Resources mMockedResources;
private final MetricsLogger mLogger;
TestableResolutionPreferenceFragment() {
super(mMockedInjector);
mMockedResources = mock(Resources.class);
doReturn(61).when(mMockedResources).getInteger(
com.android.internal.R.integer.config_externalDisplayPeakRefreshRate);
doReturn(1920).when(mMockedResources).getInteger(
com.android.internal.R.integer.config_externalDisplayPeakWidth);
doReturn(1080).when(mMockedResources).getInteger(
com.android.internal.R.integer.config_externalDisplayPeakHeight);
doReturn(true).when(mMockedResources).getBoolean(
com.android.internal.R.bool.config_refreshRateSynchronizationEnabled);
mMockedRootView = mock(View.class);
mEmptyView = new TextView(mContext);
doReturn(mEmptyView).when(mMockedRootView).findViewById(android.R.id.empty);
mLogger = mMockedMetricsLogger;
}
@Override
public PreferenceScreen getPreferenceScreen() {
return mPreferenceScreen;
}
@Override
public View getView() {
return mMockedRootView;
}
@Override
public void setEmptyView(View view) {
assertThat(view).isEqualTo(mEmptyView);
}
@Override
public View getEmptyView() {
return mEmptyView;
}
@Override
public void addPreferencesFromResource(int resource) {
mPreferenceIdFromResource = resource;
}
@Override
protected int getDisplayIdArg() {
return mDisplayIdArg;
}
@Override
protected void writePreferenceClickMetric(Preference preference) {
mLogger.writePreferenceClickMetric(preference);
}
@Override
@NonNull
protected Resources getResources(@NonNull Context context) {
return mMockedResources;
}
}
/**
* Interface allowing to mock and spy on log events.
*/
public interface MetricsLogger {
/**
* On preference click metric
*/
void writePreferenceClickMetric(Preference preference);
}
}

View File

@@ -16,13 +16,9 @@
package com.android.settings.development.bluetooth;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_VERBOSE_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_DEBUG_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_INFO_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_WARN_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_ERROR_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_DEFAULT_INDEX;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP;
import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP_PERSIST;
import static com.google.common.truth.Truth.assertThat;
@@ -37,18 +33,21 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@Ignore("b/339148064")
public class BluetoothStackLogPreferenceControllerTest {
private static final String TAG = "BluetoothStackLogPreferenceControllerTest";
private static final String COM_ANDROID_SETTINGS = "com.android.settings";
private static final String TYPE_ARRAY = "array";
@Mock private Context mContext;
private static final String XML_DEFINED_PREFERENCE_KEY = "bt_stack_log_level";
private static final String XML_DEFINED_ENTRIES_RESOURCE = "bt_stack_log_level_entries";
private static final String XML_DEFINED_VALUES_RESOURCE = "bt_stack_log_level_values";
private static final String PROPERTY_CLEARED = "";
private Context mContext;
private ListPreference mPreference;
private PreferenceManager mPreferenceManager;
@@ -61,7 +60,6 @@ public class BluetoothStackLogPreferenceControllerTest {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
if (Looper.myLooper() == null) {
@@ -71,12 +69,11 @@ public class BluetoothStackLogPreferenceControllerTest {
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mPreference = new ListPreference(mContext);
mController = new BluetoothStackLogPreferenceController(mContext);
mPreference.setKey(mController.getPreferenceKey());
mPreference.setEntries(com.android.settings.R.array.bt_stack_log_level_entries);
mPreference.setEntryValues(com.android.settings.R.array.bt_stack_log_level_values);
mPreference.setEntries(getStringArrayResourceId(XML_DEFINED_ENTRIES_RESOURCE));
mPreference.setEntryValues(getStringArrayResourceId(XML_DEFINED_VALUES_RESOURCE));
mPreferenceScreen.addPreference(mPreference);
mController.displayPreference(mPreferenceScreen);
@@ -86,134 +83,109 @@ public class BluetoothStackLogPreferenceControllerTest {
}
/**
* Test that default log level is set to INFO
* Get the resource ID associated with a resource name
*
* This looks up the resource id by name using our device's context. This way, we can avoid
* hardcoding a resource ID or value from the R class which may not match the resource IDs on
* the device under test.
*
* Usage: int valuesResId = getStringArrayResource("bt_stack_log_level_values");
* Usage: int entriesResId = getStringArrayResource("bt_stack_log_level_entries");
*
* @param res - The resource name to look up
* @return The integer resource ID corresponding to the given resource name
*/
@Test
public void verifyDefaultState_enablesDefaultLogLevelEntriesAndValuesSameSize() {
mController.onPreferenceChange(mPreference, mController.getDefaultModeIndex());
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_INFO_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_INFO_INDEX].toString());
public int getStringArrayResourceId(String res) {
return mContext.getResources().getIdentifier(res, TYPE_ARRAY, COM_ANDROID_SETTINGS);
}
/**
* Test that log level is changed to VERBOSE when VERBOSE is selected
* Test that, for each possible value a user can select, our controller properly handles the
* value to update the underlying system property _and_ set the UI entry to the proper value.
*/
@Test
public void onPreferenceChanged_enableBluetoothStackVerboseLogLevel() {
mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
.toString());
public void onPreferenceChange_withEachValue_uiSetProperlyAndAllValuesWrittenToProperties() {
for (int index = 0; index < mListValues.length; index++) {
String value = mListValues[index].toString();
String entry = mListEntries[index].toString();
final String persistedLogLevel = SystemProperties.get(
BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
.toString());
assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
mController.onPreferenceChange(mPreference, value);
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
final String currentValue = mPreference.getValue().toString();
final String currentEntry = mPreference.getEntry().toString();
final String currentSummary = mPreference.getSummary().toString();
final int currentIndex = mPreference.findIndexOfValue(currentValue);
assertThat(persistedLogLevel).isEqualTo(value);
assertThat(logLevel).isEqualTo(value);
assertThat(currentIndex).isEqualTo(index);
assertThat(currentValue).isEqualTo(value);
assertThat(currentEntry).isEqualTo(entry);
assertThat(currentSummary).isEqualTo(entry);
}
}
/**
* Test that log level is changed to DEBUG when DEBUG is selected
* Test that, for each possible log tag log level value, our controller properly handles the
* value to set the UI entry to the proper value.
*/
@Test
public void onPreferenceChanged_enableBluetoothStackDebugLogLevel() {
mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
.toString());
public void updateState_withEachValue_uiSetProperly() {
for (int index = 0; index < mListValues.length; index++) {
String value = mListValues[index].toString();
String entry = mListEntries[index].toString();
final String persistedLogLevel = SystemProperties.get(
BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
.toString());
assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, value);
SystemProperties.set(BT_LOG_LEVEL_PROP, value);
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
mController.updateState(mPreference);
final String currentValue = mPreference.getValue().toString();
final String currentEntry = mPreference.getEntry().toString();
final String currentSummary = mPreference.getSummary().toString();
final int currentIndex = mPreference.findIndexOfValue(currentValue);
assertThat(currentIndex).isEqualTo(index);
assertThat(currentValue).isEqualTo(value);
assertThat(currentEntry).isEqualTo(entry);
assertThat(currentSummary).isEqualTo(entry);
}
}
/**
* Test that log level is changed to INFO when INFO is selected
* Test that our controller reverts the log level back to a missing/default value when we're
* notified that Developer Options has been disabled.
*/
@Test
public void onPreferenceChanged_enableBluetoothStackInfoLogLevel() {
mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
.toString());
public void onDeveloperOptionsSwitchDisabled_preferenceSetToDefault() {
mController.onDeveloperOptionsSwitchDisabled();
final String persistedLogLevel = SystemProperties.get(
BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
.toString());
assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX].toString());
final String defaultEntry = mListEntries[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
final String defaultValue = mListValues[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_INFO_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_INFO_INDEX].toString());
final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
final String currentValue = mPreference.getValue().toString();
final String currentEntry = mPreference.getEntry().toString();
final String currentSummary = mPreference.getSummary().toString();
final int currentIndex = mPreference.findIndexOfValue(currentValue);
assertThat(persistedLogLevel).isEqualTo(PROPERTY_CLEARED);
assertThat(logLevel).isEqualTo(PROPERTY_CLEARED);
assertThat(currentIndex).isEqualTo(BT_LOG_LEVEL_DEFAULT_INDEX);
assertThat(currentValue).isEqualTo(defaultValue);
assertThat(currentEntry).isEqualTo(defaultEntry);
assertThat(currentSummary).isEqualTo(defaultEntry);
}
/**
* Test that log level is changed to WARN when WARN is selected
* Test that our preference key returned by our controller matches the one defined in the XML
* definition.
*/
@Test
public void onPreferenceChanged_enableBluetoothStackWarnLogLevel() {
mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
.toString());
final String persistedLogLevel = SystemProperties.get(
BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
.toString());
assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX].toString());
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_WARN_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_WARN_INDEX].toString());
}
/**
* Test that log level is changed to ERROR when ERROR is selected
*/
@Test
public void onPreferenceChanged_enableBluetoothStackErrorLogLevel() {
mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
.toString());
final String persistedLogLevel = SystemProperties.get(
BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
.toString());
assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
}
/**
* Test that preference is disabled when developer options is disabled
* Log level is also reset to default
*/
@Test
public void onDeveloperOptionsDisabled_shouldDisablePreference() {
mController.onDeveloperOptionsDisabled();
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getValue().toString()).isEqualTo(mListValues[mController
.getDefaultModeIndex()].toString());
assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries[mController
.getDefaultModeIndex()].toString());
public void getPreferenceKey_matchesXmlDefinedPreferenceKey() {
assertThat(mController.getPreferenceKey()).isEqualTo(XML_DEFINED_PREFERENCE_KEY);
}
}

View File

@@ -29,6 +29,8 @@ import android.util.Log;
import android.content.Context;
import com.android.settings.media_drm.Flags;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.preference.SwitchPreference;
@@ -65,10 +67,10 @@ public class ForceSwSecureCryptoFallbackPreferenceControllerTest {
}
@Test
@EnableFlags(Flags.FLAG_FORCE_L3_ENABLED)
public void updateState_flagEnabled_checkPreference() {
mSetFlagsRule.enableFlags(Flags.FLAG_FORCE_L3_ENABLED);
mController.updateState(mPreference);
assumeTrue(mPreference.isEnabled());
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isFalse();
assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse();
@@ -85,33 +87,22 @@ public class ForceSwSecureCryptoFallbackPreferenceControllerTest {
assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse();
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isFalse();
// Test flag rollback
mController.setChecked(true);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isTrue();
mSetFlagsRule.disableFlags(Flags.FLAG_FORCE_L3_ENABLED);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse();
}
@Test
@DisableFlags(Flags.FLAG_FORCE_L3_ENABLED)
public void updateState_flagDisabled_checkPreference() {
mSetFlagsRule.disableFlags(Flags.FLAG_FORCE_L3_ENABLED);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
@EnableFlags(Flags.FLAG_FORCE_L3_ENABLED)
public void updateState_checkWidevine() throws Exception {
try (MediaDrm drm = new MediaDrm(WIDEVINE_UUID)) {
assumeTrue(drm.getPropertyString("securityLevel").equals("L1"));
mSetFlagsRule.enableFlags(Flags.FLAG_FORCE_L3_ENABLED);
mController.updateState(mPreference);
assumeTrue(mPreference.isEnabled());
assertThat(mPreference.isEnabled()).isTrue();
} catch (UnsupportedSchemeException ex) {
assumeNoException(ex);
}
@@ -139,11 +130,11 @@ public class ForceSwSecureCryptoFallbackPreferenceControllerTest {
}
@Test
@EnableFlags(Flags.FLAG_FORCE_L3_ENABLED)
public void updateState_checkWhenWidevineReady() throws Exception {
try (MediaDrm drm = new MediaDrm(WIDEVINE_UUID)) {
if (drm.getPropertyString("securityLevel").equals("L1")) {
String version = drm.getPropertyString(MediaDrm.PROPERTY_VERSION);
mSetFlagsRule.enableFlags(Flags.FLAG_FORCE_L3_ENABLED);
mController.updateState(mPreference);
if (Integer.parseInt(version.split("\\.", 2)[0]) >= 19) {
assertThat(mPreference.isEnabled()).isTrue();

View File

@@ -22,14 +22,21 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.os.Looper;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import androidx.lifecycle.LifecycleOwner;
@@ -45,6 +52,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -53,6 +61,9 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class BuildNumberPreferenceControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule =
DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String KEY_BUILD_NUMBER = "build_number";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -60,6 +71,7 @@ public class BuildNumberPreferenceControllerTest {
private Context mContext;
private UserManager mUserManager;
private BiometricManager mBiometricManager;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private FakeFeatureFactory mFactory;
@@ -76,7 +88,13 @@ public class BuildNumberPreferenceControllerTest {
mContext = spy(ApplicationProvider.getApplicationContext());
mUserManager = (UserManager) spy(mContext.getSystemService(Context.USER_SERVICE));
mBiometricManager = spy(mContext.getSystemService(BiometricManager.class));
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
mFactory = FakeFeatureFactory.setupForTest();
mLifecycleOwner = () -> mLifecycle;
@@ -156,7 +174,7 @@ public class BuildNumberPreferenceControllerTest {
@Test
public void onActivityResult_notConfirmPasswordRequest_doNothing() {
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF + 1,
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF + 2,
Activity.RESULT_OK,
null);
@@ -177,6 +195,7 @@ public class BuildNumberPreferenceControllerTest {
@Test
@UiThreadTest
@RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onActivityResult_confirmPasswordRequestCompleted_enableDevPref() {
when(mUserManager.isAdminUser()).thenReturn(true);
@@ -188,4 +207,56 @@ public class BuildNumberPreferenceControllerTest {
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onActivityResult_confirmPasswordRequestCompleted_launchBiometricPrompt() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
Activity.RESULT_OK,
null);
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
verify(mFragment).startActivityForResult(any(),
eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF));
}
@Test
@UiThreadTest
@RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
public void onActivityResult_confirmPasswordRequestCompleted_mandatoryBiometricsError() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE);
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
Activity.RESULT_OK,
null);
assertThat(activityResultHandled).isTrue();
verify(mFragment, never()).startActivityForResult(any(),
eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF));
}
@Test
public void onActivityResult_confirmBiometricAuthentication_enableDevPref() {
when(mUserManager.isAdminUser()).thenReturn(true);
Looper.prepare();
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF,
Activity.RESULT_OK,
null);
assertThat(activityResultHandled).isTrue();
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isTrue();
}
}

View File

@@ -16,7 +16,6 @@
package com.android.settings.fingerprint2.domain.interactor
import android.content.Context
import android.content.Intent
import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.SensorLocationInternal
@@ -30,23 +29,37 @@ import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.os.CancellationSignal
import android.os.Handler
import androidx.test.core.app.ApplicationProvider
import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepositoryImpl
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepository
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSettingsRepositoryImpl
import com.android.settings.biometrics.fingerprint2.data.repository.UserRepo
import com.android.settings.biometrics.fingerprint2.domain.interactor.AuthenticateInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.CanEnrollFingerprintsInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollFingerprintInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrolledFingerprintsInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.GenerateChallengeInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.RemoveFingerprintsInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.RenameFingerprintsInteractorImpl
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.CanEnrollFingerprintsInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrollFingerprintInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.EnrolledFingerprintsInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.GenerateChallengeInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RemoveFingerprintInteractor
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.RenameFingerprintInteractor
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.EnrollReason
import com.android.settings.biometrics.fingerprint2.lib.model.FingerEnrollState
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintAuthAttemptModel
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintData
import com.android.settings.biometrics.fingerprint2.lib.model.FingerprintFlow
import com.android.settings.password.ChooseLockSettingsHelper
import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.toFingerprintSensor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.last
import kotlinx.coroutines.launch
@@ -75,13 +88,28 @@ import org.mockito.stubbing.OngoingStubbing
class FingerprintManagerInteractorTest {
@JvmField @Rule var rule = MockitoJUnit.rule()
private lateinit var underTest: FingerprintManagerInteractor
private var context: Context = ApplicationProvider.getApplicationContext()
private lateinit var enrolledFingerprintsInteractorUnderTest: EnrolledFingerprintsInteractor
private lateinit var generateChallengeInteractorUnderTest: GenerateChallengeInteractor
private lateinit var removeFingerprintsInteractorUnderTest: RemoveFingerprintInteractor
private lateinit var renameFingerprintsInteractorUnderTest: RenameFingerprintInteractor
private lateinit var authenticateInteractorImplUnderTest: AuthenticateInteractorImpl
private lateinit var canEnrollFingerprintsInteractorUnderTest: CanEnrollFingerprintsInteractor
private lateinit var enrollInteractorUnderTest: EnrollFingerprintInteractor
private val userId = 0
private var backgroundDispatcher = StandardTestDispatcher()
@Mock private lateinit var fingerprintManager: FingerprintManager
@Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider
private var testScope = TestScope(backgroundDispatcher)
private var backgroundScope = testScope.backgroundScope
private val flow: FingerprintFlow = Default
private val maxFingerprints = 5
private val currUser = MutableStateFlow(0)
private val userRepo =
object : UserRepo {
override val currentUser: Flow<Int> = currUser
}
@Before
fun setup() {
@@ -89,7 +117,7 @@ class FingerprintManagerInteractorTest {
FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
maxFingerprints,
listOf<ComponentInfoInternal>(),
FingerprintSensorProperties.TYPE_POWER_BUTTON,
false /* halControlsIllumination */,
@@ -97,20 +125,37 @@ class FingerprintManagerInteractorTest {
listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT),
)
.toFingerprintSensor()
val fingerprintSensorRepository =
object : FingerprintSensorRepository {
override val fingerprintSensor: Flow<FingerprintSensor> = flowOf(sensor)
override val hasSideFps: Flow<Boolean> = flowOf(false)
}
underTest =
FingerprintManagerInteractorImpl(
context,
backgroundDispatcher,
val settingsRepository = FingerprintSettingsRepositoryImpl(maxFingerprints)
val fingerprintEnrollmentRepository =
FingerprintEnrollmentRepositoryImpl(
fingerprintManager,
fingerprintSensorRepository,
gateKeeperPasswordProvider,
FingerprintEnrollInteractorImpl(context, fingerprintManager, Default),
userRepo,
settingsRepository,
backgroundDispatcher,
backgroundScope,
)
enrolledFingerprintsInteractorUnderTest =
EnrolledFingerprintsInteractorImpl(fingerprintManager, userId)
generateChallengeInteractorUnderTest =
GenerateChallengeInteractorImpl(fingerprintManager, userId, gateKeeperPasswordProvider)
removeFingerprintsInteractorUnderTest =
RemoveFingerprintsInteractorImpl(fingerprintManager, userId)
renameFingerprintsInteractorUnderTest =
RenameFingerprintsInteractorImpl(fingerprintManager, userId, backgroundDispatcher)
authenticateInteractorImplUnderTest = AuthenticateInteractorImpl(fingerprintManager, userId)
canEnrollFingerprintsInteractorUnderTest =
CanEnrollFingerprintsInteractorImpl(fingerprintEnrollmentRepository)
enrollInteractorUnderTest = EnrollFingerprintInteractorImpl(userId, fingerprintManager, flow)
}
@Test
@@ -119,7 +164,8 @@ class FingerprintManagerInteractorTest {
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(emptyList())
val emptyFingerprintList: List<Fingerprint> = emptyList()
assertThat(underTest.enrolledFingerprints.last()).isEqualTo(emptyFingerprintList)
assertThat(enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last())
.isEqualTo(emptyFingerprintList)
}
@Test
@@ -129,7 +175,7 @@ class FingerprintManagerInteractorTest {
val fingerprintList: List<Fingerprint> = listOf(expected)
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
val list = underTest.enrolledFingerprints.last()
val list = enrolledFingerprintsInteractorUnderTest.enrolledFingerprints.last()
assertThat(list!!.size).isEqualTo(fingerprintList.size)
val actual = list[0]
assertThat(actual.name).isEqualTo(expected.name)
@@ -138,24 +184,51 @@ class FingerprintManagerInteractorTest {
}
@Test
fun testCanEnrollFingerprint() =
fun testCanEnrollFingerprintSucceeds() =
testScope.runTest {
val fingerprintList1: List<Fingerprint> =
val fingerprintList: List<Fingerprint> =
listOf(
Fingerprint("Finger 1,", 2, 3L),
Fingerprint("Finger 2,", 3, 3L),
Fingerprint("Finger 3,", 4, 3L),
Fingerprint("Finger 1", 2, 3L),
Fingerprint("Finger 2", 3, 3L),
Fingerprint("Finger 3", 4, 3L),
)
val fingerprintList2: List<Fingerprint> =
fingerprintList1.plus(
listOf(Fingerprint("Finger 4,", 5, 3L), Fingerprint("Finger 5,", 6, 3L))
)
whenever(fingerprintManager.getEnrolledFingerprints(anyInt()))
.thenReturn(fingerprintList1)
.thenReturn(fingerprintList2)
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
assertThat(underTest.canEnrollFingerprints.last()).isTrue()
assertThat(underTest.canEnrollFingerprints.last()).isFalse()
var result: Boolean? = null
val job =
testScope.launch {
canEnrollFingerprintsInteractorUnderTest.canEnrollFingerprints.collect { result = it }
}
runCurrent()
job.cancelAndJoin()
assertThat(result).isTrue()
}
@Test
fun testCanEnrollFingerprintFails() =
testScope.runTest {
val fingerprintList: List<Fingerprint> =
listOf(
Fingerprint("Finger 1", 2, 3L),
Fingerprint("Finger 2", 3, 3L),
Fingerprint("Finger 3", 4, 3L),
Fingerprint("Finger 4", 5, 3L),
Fingerprint("Finger 5", 6, 3L),
)
whenever(fingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(fingerprintList)
var result: Boolean? = null
val job =
testScope.launch {
canEnrollFingerprintsInteractorUnderTest.canEnrollFingerprints.collect { result = it }
}
runCurrent()
job.cancelAndJoin()
assertThat(result).isFalse()
}
@Test
@@ -178,7 +251,8 @@ class FingerprintManagerInteractorTest {
argumentCaptor()
var result: Pair<Long, ByteArray?>? = null
val job = testScope.launch { result = underTest.generateChallenge(1L) }
val job =
testScope.launch { result = generateChallengeInteractorUnderTest.generateChallenge(1L) }
runCurrent()
verify(fingerprintManager).generateChallenge(anyInt(), capture(generateChallengeCallback))
@@ -201,7 +275,10 @@ class FingerprintManagerInteractorTest {
var result: Boolean? = null
val job =
testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) }
testScope.launch {
result =
removeFingerprintsInteractorUnderTest.removeFingerprint(fingerprintViewModelToRemove)
}
runCurrent()
verify(fingerprintManager)
@@ -224,7 +301,10 @@ class FingerprintManagerInteractorTest {
var result: Boolean? = null
val job =
testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) }
testScope.launch {
result =
removeFingerprintsInteractorUnderTest.removeFingerprint(fingerprintViewModelToRemove)
}
runCurrent()
verify(fingerprintManager)
@@ -246,7 +326,7 @@ class FingerprintManagerInteractorTest {
testScope.runTest {
val fingerprintToRename = FingerprintData("Finger 2", 1, 2L)
underTest.renameFingerprint(fingerprintToRename, "Woo")
renameFingerprintsInteractorUnderTest.renameFingerprint(fingerprintToRename, "Woo")
verify(fingerprintManager).rename(eq(fingerprintToRename.fingerId), anyInt(), safeEq("Woo"))
}
@@ -257,7 +337,7 @@ class FingerprintManagerInteractorTest {
val fingerprint = Fingerprint("Woooo", 100, 101L)
var result: FingerprintAuthAttemptModel? = null
val job = launch { result = underTest.authenticate() }
val job = launch { result = authenticateInteractorImplUnderTest.authenticate() }
val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> = argumentCaptor()
@@ -284,7 +364,7 @@ class FingerprintManagerInteractorTest {
fun testAuth_lockout() =
testScope.runTest {
var result: FingerprintAuthAttemptModel? = null
val job = launch { result = underTest.authenticate() }
val job = launch { result = authenticateInteractorImplUnderTest.authenticate() }
val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> = argumentCaptor()
@@ -314,7 +394,7 @@ class FingerprintManagerInteractorTest {
val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null
val job = launch {
underTest
enrollInteractorUnderTest
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
.collect { result = it }
}
@@ -343,7 +423,7 @@ class FingerprintManagerInteractorTest {
val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null
val job = launch {
underTest
enrollInteractorUnderTest
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
.collect { result = it }
}
@@ -372,7 +452,7 @@ class FingerprintManagerInteractorTest {
val token = byteArrayOf(5, 3, 2)
var result: FingerEnrollState? = null
val job = launch {
underTest
enrollInteractorUnderTest
.enroll(token, EnrollReason.FindSensor, FingerprintEnrollOptions.Builder().build())
.collect { result = it }
}

View File

@@ -99,9 +99,10 @@ class FingerprintEnrollFindSensorViewModelV2Test {
backgroundViewModel.inForeground()
enrollViewModel =
FingerprintEnrollViewModel(
fakeFingerprintManagerInteractor,
gatekeeperViewModel,
navigationViewModel,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
accessibilityInteractor =
object : AccessibilityInteractor {

View File

@@ -49,8 +49,7 @@ class RFPSIconTouchViewModelTest {
fun setup() {
Dispatchers.setMain(backgroundDispatcher)
testScope = TestScope(backgroundDispatcher)
rfpsIconTouchViewModel =
RFPSIconTouchViewModel()
rfpsIconTouchViewModel = RFPSIconTouchViewModel()
}
@After

View File

@@ -88,9 +88,10 @@ class FingerprintEnrollEnrollingViewModelTest {
backgroundViewModel.inForeground()
val fingerprintEnrollViewModel =
FingerprintEnrollViewModel(
fakeFingerprintManagerInteractor,
gateKeeperViewModel,
navigationViewModel,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
enrollEnrollingViewModel =
FingerprintEnrollEnrollingViewModel(fingerprintEnrollViewModel, backgroundViewModel)

View File

@@ -67,10 +67,11 @@ class FingerprintSettingsNavigationViewModelTest {
underTest =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
null,
null,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
}
@@ -272,10 +273,11 @@ class FingerprintSettingsNavigationViewModelTest {
underTest =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
token,
challenge,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
@@ -299,10 +301,11 @@ class FingerprintSettingsNavigationViewModelTest {
underTest =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
token,
challenge,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
@@ -331,10 +334,11 @@ class FingerprintSettingsNavigationViewModelTest {
underTest =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
token,
challenge,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsNavigationViewModel::class.java)

View File

@@ -73,19 +73,25 @@ class FingerprintSettingsViewModelTest {
navigationViewModel =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
null,
null,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsViewModel::class.java)
}
@@ -114,14 +120,7 @@ class FingerprintSettingsViewModelTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintData("a", 1, 3L))
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var authAttempt: FingerprintAuthAttemptModel? = null
val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
@@ -156,14 +155,7 @@ class FingerprintSettingsViewModelTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintData("a", 1, 3L))
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var authAttempt: FingerprintAuthAttemptModel? = null
val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
@@ -198,14 +190,7 @@ class FingerprintSettingsViewModelTest {
val success = FingerprintAuthAttemptModel.Success(1)
fakeFingerprintManagerInteractor.authenticateAttempt = success
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var authAttempt: FingerprintAuthAttemptModel? = null
@@ -225,14 +210,7 @@ class FingerprintSettingsViewModelTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(fingerprintToDelete)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var dialog: PreferenceViewModel? = null
val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
@@ -261,14 +239,7 @@ class FingerprintSettingsViewModelTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(fingerprintToRename)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var dialog: PreferenceViewModel? = null
val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
@@ -299,14 +270,7 @@ class FingerprintSettingsViewModelTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(fingerprintToDelete)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
var dialog: PreferenceViewModel? = null
val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
@@ -390,6 +354,22 @@ class FingerprintSettingsViewModelTest {
assertThat(authAttempt).isEqualTo(null)
}
private fun recreateSettingsViewModel() {
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
backgroundDispatcher,
navigationViewModel,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
fakeFingerprintManagerInteractor,
)
.create(FingerprintSettingsViewModel::class.java)
}
private fun setupAuth(): MutableList<FingerprintData> {
fakeFingerprintManagerInteractor.sensorProp =
FingerprintSensorPropertiesInternal(
@@ -409,14 +389,7 @@ class FingerprintSettingsViewModelTest {
val success = FingerprintAuthAttemptModel.Success(1)
fakeFingerprintManagerInteractor.authenticateAttempt = success
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
recreateSettingsViewModel()
return fingerprints
}

View File

@@ -26,6 +26,7 @@ import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_RESTRICTED
import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNKNOWN
import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED
import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils.UNLIMITED_EXPIRE_TIME
import com.android.settings.testutils.FakeFeatureFactory
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -51,9 +52,14 @@ class AppOptModeSharedPreferencesUtilsTest {
@Spy
private var testBatteryOptimizeUtils = spy(BatteryOptimizeUtils(context, UID, PACKAGE_NAME))
private lateinit var featureFactory: FakeFeatureFactory
@Before
fun setup() {
AppOptModeSharedPreferencesUtils.clearAll(context)
featureFactory = FakeFeatureFactory.setupForTest()
whenever(featureFactory.powerUsageFeatureProvider.isForceExpireAppOptimizationModeEnabled)
.thenReturn(false)
}
@After
@@ -77,8 +83,17 @@ class AppOptModeSharedPreferencesUtilsTest {
}
@Test
fun updateAppOptModeExpirationInternal_withExpirationTime_verifyData() {
insertAppOptModeEventForTest(expirationTime = 1000L)
fun updateAppOptModeExpirationInternal_withoutExpirationTime_verifyEmptyList() {
insertAppOptModeEventForTest(expirationTime = UNLIMITED_EXPIRE_TIME)
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@Test
fun updateAppOptModeExpirationInternal_setOptimizedModeWithFlagEnabled_verifyData() {
whenever(featureFactory.powerUsageFeatureProvider.isRestrictedModeOverwriteEnabled)
.thenReturn(true)
insertAppOptModeEventForTest(expirationTime = 1000L, mode = MODE_OPTIMIZED)
val events = AppOptModeSharedPreferencesUtils.getAllEvents(context)
@@ -93,8 +108,46 @@ class AppOptModeSharedPreferencesUtilsTest {
}
@Test
fun updateAppOptModeExpirationInternal_withoutExpirationTime_verifyEmptyList() {
insertAppOptModeEventForTest(expirationTime = UNLIMITED_EXPIRE_TIME)
fun updateAppOptModeExpirationInternal_setOptimizedModeWithFlagDisabled_verifyData() {
whenever(featureFactory.powerUsageFeatureProvider.isRestrictedModeOverwriteEnabled)
.thenReturn(false)
insertAppOptModeEventForTest(expirationTime = 1000L, mode = MODE_OPTIMIZED)
val events = AppOptModeSharedPreferencesUtils.getAllEvents(context)
assertThat(events).hasSize(1)
assertAppOptimizationModeEventInfo(
events[0],
UID,
PACKAGE_NAME,
MODE_OPTIMIZED,
expirationTime = 1000L
)
}
@Test
fun updateAppOptModeExpirationInternal_setRestrictedModeWithFlagEnabled_verifyData() {
whenever(featureFactory.powerUsageFeatureProvider.isRestrictedModeOverwriteEnabled)
.thenReturn(true)
insertAppOptModeEventForTest(expirationTime = 1000L, mode = MODE_RESTRICTED)
val events = AppOptModeSharedPreferencesUtils.getAllEvents(context)
assertThat(events).hasSize(1)
assertAppOptimizationModeEventInfo(
events[0],
UID,
PACKAGE_NAME,
MODE_RESTRICTED,
expirationTime = 1000L
)
}
@Test
fun updateAppOptModeExpirationInternal_setRestrictedModeWithFlagDisabled_verifyEmptyList() {
whenever(featureFactory.powerUsageFeatureProvider.isRestrictedModeOverwriteEnabled)
.thenReturn(false)
insertAppOptModeEventForTest(expirationTime = 1000L, mode = MODE_RESTRICTED)
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@@ -126,6 +179,20 @@ class AppOptModeSharedPreferencesUtilsTest {
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@Test
fun resetExpiredAppOptModeBeforeTimestamp_forceExpiredData_verifyEmptyList() {
whenever(featureFactory.powerUsageFeatureProvider.isForceExpireAppOptimizationModeEnabled)
.thenReturn(true)
insertAppOptModeEventForTest(expirationTime = 1000L)
AppOptModeSharedPreferencesUtils.resetExpiredAppOptModeBeforeTimestamp(
context,
queryTimestampMs = 999L
)
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@Test
fun resetExpiredAppOptModeBeforeTimestamp_noExpiredData_verifyData() {
insertAppOptModeEventForTest(expirationTime = 1000L)
@@ -217,14 +284,14 @@ class AppOptModeSharedPreferencesUtilsTest {
assertThat(currentOptMode).isEqualTo(MODE_RESTRICTED)
}
private fun insertAppOptModeEventForTest(expirationTime: Long) {
private fun insertAppOptModeEventForTest(expirationTime: Long, mode: Int = MODE_OPTIMIZED) {
whenever(testBatteryOptimizeUtils?.isOptimizeModeMutable).thenReturn(true)
whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)).thenReturn(MODE_OPTIMIZED)
whenever(testBatteryOptimizeUtils?.getAppOptimizationMode(true)).thenReturn(mode)
AppOptModeSharedPreferencesUtils.updateAppOptModeExpirationInternal(
context,
mutableListOf(UID),
mutableListOf(PACKAGE_NAME),
mutableListOf(MODE_OPTIMIZED),
mutableListOf(mode),
longArrayOf(expirationTime),
) { _: Int, _: String ->
testBatteryOptimizeUtils

View File

@@ -17,13 +17,11 @@
package com.android.settings.localepicker;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Looper;
@@ -66,14 +64,6 @@ public class TermsOfAddressCategoryControllerTest {
Locale.setDefault(mCacheLocale);
}
@Test
public void getAvailabilityStatus_returnUnavailable() {
Locale.setDefault(Locale.forLanguageTag("fr-CA"));
assertThat(mTermsOfAddressCategoryController.getAvailabilityStatus()).isEqualTo(
CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_returnAvailable() {
Locale.setDefault(Locale.forLanguageTag("fr-FR"));

View File

@@ -1,310 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network;
import static com.android.settings.network.InternetUpdater.INTERNET_NETWORKS_AVAILABLE;
import static com.android.settings.network.InternetUpdater.INTERNET_WIFI;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.R;
import com.android.settings.testutils.ResourcesUtils;
import com.android.settings.wifi.WifiPickerTrackerHelper;
import com.android.settings.wifi.WifiSummaryUpdater;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
import com.android.wifitrackerlib.HotspotNetworkEntry;
import com.android.wifitrackerlib.StandardWifiEntry;
import com.android.wifitrackerlib.WifiPickerTracker;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class InternetPreferenceControllerTest {
private static final String TEST_SUMMARY = "test summary";
private static final String TEST_ALTERNATE_SUMMARY = "test alternate summary";
private static final String NOT_CONNECTED = "Not connected";
private static final String SUB_ID_1 = "1";
private static final String SUB_ID_2 = "2";
private static final String INVALID_SUB_ID = "-1";
private static final String DISPLAY_NAME_1 = "Sub 1";
private static final String DISPLAY_NAME_2 = "Sub 2";
private static final String SUB_MCC_1 = "123";
private static final String SUB_MNC_1 = "456";
private static final String SUB_MCC_2 = "223";
private static final String SUB_MNC_2 = "456";
private static final String SUB_COUNTRY_ISO_1 = "Sub 1";
private static final String SUB_COUNTRY_ISO_2 = "Sub 2";
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private SubscriptionInfoEntity mActiveSubInfo;
@Mock
private SubscriptionInfoEntity mDefaultDataSubInfo;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private LifecycleOwner mLifecycleOwner;
@Mock
private WifiManager mWifiManager;
@Mock
private WifiSummaryUpdater mSummaryHelper;
@Mock
private WifiPickerTrackerHelper mWifiPickerTrackerHelper;
@Mock
private WifiPickerTracker mWifiPickerTracker;
@Mock
private HotspotNetworkEntry mHotspotNetworkEntry;
private LifecycleRegistry mLifecycleRegistry;
private MockInternetPreferenceController mController;
private PreferenceScreen mScreen;
private Preference mPreference;
private List<SubscriptionInfoEntity> mSubscriptionInfoEntityList = new ArrayList<>();
@Before
public void setUp() {
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
when(mContext.getSystemService(NetworkScoreManager.class))
.thenReturn(mock(NetworkScoreManager.class));
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED);
when(mWifiPickerTrackerHelper.getWifiPickerTracker()).thenReturn(mWifiPickerTracker);
when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(null /* WifiEntry */);
when(mHotspotNetworkEntry.getAlternateSummary()).thenReturn(TEST_ALTERNATE_SUMMARY);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
mController = new MockInternetPreferenceController(mContext, mock(Lifecycle.class),
mLifecycleOwner);
mController.sIconMap.put(INTERNET_WIFI, 0);
mController.mWifiPickerTrackerHelper = mWifiPickerTrackerHelper;
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
mPreference = new Preference(mContext);
mPreference.setKey(InternetPreferenceController.KEY);
mScreen.addPreference(mPreference);
}
private class MockInternetPreferenceController extends
com.android.settings.network.InternetPreferenceController {
private int mDefaultDataSubscriptionId;
public MockInternetPreferenceController(Context context, Lifecycle lifecycle,
LifecycleOwner lifecycleOwner) {
super(context, lifecycle, lifecycleOwner);
}
private List<SubscriptionInfoEntity> mSubscriptionInfoEntity;
@Override
protected List<SubscriptionInfoEntity> getSubscriptionInfoList() {
return mSubscriptionInfoEntity;
}
public void setSubscriptionInfoList(List<SubscriptionInfoEntity> list) {
mSubscriptionInfoEntity = list;
}
@Override
protected int getDefaultDataSubscriptionId() {
return mDefaultDataSubscriptionId;
}
public void setDefaultDataSubscriptionId(int subscriptionId) {
mDefaultDataSubscriptionId = subscriptionId;
}
}
private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, int slotId,
int carrierId, String displayName, String mcc, String mnc, String countryIso,
int cardId, boolean isVisible, boolean isValid, boolean isActive, boolean isAvailable,
boolean isActiveData) {
return new SubscriptionInfoEntity(subId, slotId, carrierId,
displayName, displayName, 0, mcc, mnc, countryIso, false, cardId,
TelephonyManager.DEFAULT_PORT_INDEX, false, null,
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, isVisible,
"1234567890", true, false, isValid, true, isActive, isAvailable, isActiveData);
}
@Test
public void isAvailable_shouldMatchPrefFlag() {
assertThat(mController.isAvailable()).isEqualTo(
mContext.getResources().getBoolean(R.bool.config_show_internet_settings));
}
@Test
@UiThreadTest
public void onResume_shouldRegisterCallback() {
mController.onResume();
verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class),
any(int.class));
verify(mConnectivityManager).registerNetworkCallback(
any(NetworkRequest.class),
any(ConnectivityManager.NetworkCallback.class),
any(Handler.class));
}
@Test
@UiThreadTest
public void onPause_shouldUnregisterCallback() {
mController.onResume();
mController.onPause();
verify(mContext, times(2)).unregisterReceiver(any(BroadcastReceiver.class));
verify(mConnectivityManager, times(2)).unregisterNetworkCallback(
any(ConnectivityManager.NetworkCallback.class));
}
@Test
public void onSummaryChanged_internetWifi_updateSummary() {
when(mSummaryHelper.getSummary()).thenReturn(TEST_SUMMARY);
mController.mSummaryHelper = mSummaryHelper;
mController.onInternetTypeChanged(INTERNET_WIFI);
mController.displayPreference(mScreen);
mController.onSummaryChanged(TEST_SUMMARY);
assertThat(mPreference.getSummary()).isEqualTo(TEST_SUMMARY);
}
@Test
public void onSummaryChanged_internetNetworksAvailable_notUpdateSummary() {
when(mSummaryHelper.getSummary()).thenReturn(TEST_SUMMARY);
mController.mSummaryHelper = mSummaryHelper;
mController.onInternetTypeChanged(INTERNET_NETWORKS_AVAILABLE);
mController.displayPreference(mScreen);
mPreference.setSummary(NOT_CONNECTED);
mController.onSummaryChanged(TEST_SUMMARY);
assertThat(mPreference.getSummary()).isNotEqualTo(TEST_SUMMARY);
}
@Test
public void updateCellularSummary_getNullSubscriptionInfo_shouldNotCrash() {
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
mController.updateCellularSummary();
}
@Test
public void updateCellularSummary_getActiveSubscriptionInfo_cbrs() {
mController.setDefaultDataSubscriptionId(Integer.parseInt(SUB_ID_2));
mActiveSubInfo = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, false, true, true, true, true);
mDefaultDataSubInfo = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, false, true, true, true, false);
mSubscriptionInfoEntityList.add(mActiveSubInfo);
mSubscriptionInfoEntityList.add(mDefaultDataSubInfo);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
mController.displayPreference(mScreen);
mController.updateCellularSummary();
assertThat(mPreference.getSummary()).isEqualTo(DISPLAY_NAME_2);
mActiveSubInfo = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true, true, true);
mSubscriptionInfoEntityList.add(mActiveSubInfo);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
mController.onAvailableSubInfoChanged(mSubscriptionInfoEntityList);
final String expectedSummary =
ResourcesUtils.getResourcesString(mContext, "mobile_data_temp_using",
DISPLAY_NAME_1);
mController.updateCellularSummary();
assertThat(mPreference.getSummary()).isEqualTo(expectedSummary);
}
@Test
public void updateHotspotNetwork_isHotspotNetworkEntry_updateAlternateSummary() {
when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(mHotspotNetworkEntry);
mController.onInternetTypeChanged(INTERNET_WIFI);
mController.displayPreference(mScreen);
mPreference.setSummary(TEST_SUMMARY);
mController.updateHotspotNetwork();
assertThat(mPreference.getSummary().toString()).isEqualTo(TEST_ALTERNATE_SUMMARY);
}
@Test
public void updateHotspotNetwork_notHotspotNetworkEntry_notChangeSummary() {
when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(mock(StandardWifiEntry.class));
mController.onInternetTypeChanged(INTERNET_WIFI);
mController.displayPreference(mScreen);
mPreference.setSummary(TEST_SUMMARY);
mController.updateHotspotNetwork();
assertThat(mPreference.getSummary().toString()).isEqualTo(TEST_SUMMARY);
}
@Test
public void updateHotspotNetwork_hotspotNetworkNotEnabled_returnFalse() {
mController.mWifiPickerTrackerHelper = null;
assertThat(mController.updateHotspotNetwork()).isFalse();
}
}

View File

@@ -1,187 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network;
import static androidx.lifecycle.Lifecycle.Event;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedPreference;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class MobileNetworkPreferenceControllerTest {
private Context mContext;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private UserManager mUserManager;
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
@Mock
private LifecycleOwner mLifecycleOwner;
private LifecycleRegistry mLifecycleRegistry;
private MobileNetworkPreferenceController mController;
private Preference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mSubscriptionManager.createForAllUserProfiles()).thenReturn(mSubscriptionManager);
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mPreferenceManager = new PreferenceManager(mContext);
mScreen = mPreferenceManager.createPreferenceScreen(mContext);
mPreference = new Preference(mContext);
mPreference.setKey(MobileNetworkPreferenceController.KEY_MOBILE_NETWORK_SETTINGS);
mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
}
@Test
public void secondaryUser_prefIsNotAvailable() {
when(mUserManager.isAdminUser()).thenReturn(false);
when(mTelephonyManager.isDataCapable()).thenReturn(true);
mController = new MobileNetworkPreferenceController(mContext);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void wifiOnly_prefIsNotAvailable() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mTelephonyManager.isDataCapable()).thenReturn(false);
mController = new MobileNetworkPreferenceController(mContext);
assertThat(mController.isAvailable()).isFalse();
}
@Test
@UiThreadTest
public void goThroughLifecycle_isAvailable_shouldListenToServiceChange() {
mController = spy(new MobileNetworkPreferenceController(mContext));
mLifecycleRegistry.addObserver(mController);
doReturn(true).when(mController).isAvailable();
mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
verify(mController).onStart();
verify(mTelephonyManager).registerTelephonyCallback(
mContext.getMainExecutor(), mController.mTelephonyCallback);
mLifecycleRegistry.handleLifecycleEvent(Event.ON_STOP);
verify(mController).onStop();
verify(mTelephonyManager).unregisterTelephonyCallback(mController.mTelephonyCallback);
}
@Test
@UiThreadTest
public void serviceStateChange_shouldUpdatePrefSummary() {
final String testCarrierName = "test";
mController = spy(new MobileNetworkPreferenceController(mContext));
mLifecycleRegistry.addObserver(mController);
doReturn(true).when(mController).isAvailable();
mScreen.addPreference(mPreference);
// Display pref and go through lifecycle to set up listener.
mController.displayPreference(mScreen);
mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
verify(mController).onStart();
verify(mTelephonyManager).registerTelephonyCallback(
mContext.getMainExecutor(), mController.mTelephonyCallback);
doReturn(testCarrierName).when(mController).getSummary();
mController.mTelephonyCallback.onServiceStateChanged(null);
// Carrier name should be set.
Assert.assertEquals(mPreference.getSummary(), testCarrierName);
}
@Test
public void airplaneModeTurnedOn_shouldDisablePreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Global.AIRPLANE_MODE_ON, 1);
mController = spy(new MobileNetworkPreferenceController(mContext));
final RestrictedPreference mPreference = new RestrictedPreference(mContext);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void airplaneModeTurnedOffAndNoUserRestriction_shouldEnablePreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Global.AIRPLANE_MODE_ON, 0);
mController = spy(new MobileNetworkPreferenceController(mContext));
final RestrictedPreference mPreference = new RestrictedPreference(mContext);
mPreference.setDisabledByAdmin(null);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void airplaneModeTurnedOffAndHasUserRestriction_shouldDisablePreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Global.AIRPLANE_MODE_ON, 0);
mController = spy(new MobileNetworkPreferenceController(mContext));
final RestrictedPreference mPreference = new RestrictedPreference(mContext);
mPreference.setDisabledByAdmin(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
}

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.spy;
import android.content.Context;
import android.os.Looper;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.annotation.UiThreadTest;
@@ -54,11 +55,11 @@ public class NetworkProviderCallsSmsFragmentTest {
if (Looper.myLooper() == null) {
Looper.prepare();
}
mSetFlagsRule.disableFlags(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED);
}
@Test
@UiThreadTest
@DisableFlags(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void isPageSearchEnabled_shouldIncludeFragmentXml() {
mPreferenceKeyList =
NetworkProviderCallsSmsFragment.SEARCH_INDEX_DATA_PROVIDER

View File

@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import androidx.lifecycle.LifecycleOwner;
@@ -63,12 +62,6 @@ public class NetworkProviderSimListControllerTest {
private static final String KEY_PREFERENCE_CATEGORY_SIM = "provider_model_sim_category";
private static final String DISPLAY_NAME_1 = "Sub 1";
private static final String DISPLAY_NAME_2 = "Sub 2";
private static final String SUB_MCC_1 = "123";
private static final String SUB_MNC_1 = "456";
private static final String SUB_MCC_2 = "223";
private static final String SUB_MNC_2 = "456";
private static final String SUB_COUNTRY_ISO_1 = "Sub 1";
private static final String SUB_COUNTRY_ISO_2 = "Sub 2";
@Mock
private SubscriptionInfoEntity mSubInfo1;
@@ -140,12 +133,9 @@ public class NetworkProviderSimListControllerTest {
}
private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, int slotId,
int carrierId, String displayName, String mcc, String mnc, String countryIso,
int cardId, boolean isValid, boolean isActive, boolean isAvailable) {
return new SubscriptionInfoEntity(subId, slotId, carrierId, displayName, displayName, 0,
mcc, mnc, countryIso, false, cardId, TelephonyManager.DEFAULT_PORT_INDEX, false,
null, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, false,
"1234567890", true, false, isValid, true, isActive, isAvailable, false);
String displayName, boolean isValid, boolean isActive) {
return new SubscriptionInfoEntity(subId, slotId, false, false, displayName, false,
false, isValid, isActive, false);
}
private String setSummaryResId(String resName, String value) {
@@ -159,8 +149,7 @@ public class NetworkProviderSimListControllerTest {
@Test
@UiThreadTest
public void getSummary_tapToActivePSim() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, false, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, DISPLAY_NAME_1, true, false);
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
displayPreferenceWithLifecycle();
@@ -172,8 +161,7 @@ public class NetworkProviderSimListControllerTest {
@Test
@UiThreadTest
public void getSummary_inactivePSim() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, false, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, DISPLAY_NAME_1, true, false);
doReturn(true).when(mSubscriptionManager).canDisablePhysicalSubscription();
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
@@ -187,8 +175,7 @@ public class NetworkProviderSimListControllerTest {
@Test
@UiThreadTest
public void getSummary_defaultCalls() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, DISPLAY_NAME_1, true, true);
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
@@ -209,8 +196,7 @@ public class NetworkProviderSimListControllerTest {
defaultConfig.append(setSummaryResId("default_active_sim_calls"))
.append(", ")
.append(setSummaryResId("default_active_sim_sms"));
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, DISPLAY_NAME_1, true, true);
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
@@ -228,10 +214,8 @@ public class NetworkProviderSimListControllerTest {
@Test
@UiThreadTest
public void getAvailablePhysicalSubscription_withTwoPhysicalSims_returnTwo() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, DISPLAY_NAME_1, true, true);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, DISPLAY_NAME_2, true, true);
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);

View File

@@ -38,8 +38,6 @@ import android.telephony.UiccSlotMapping;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +45,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -81,25 +78,6 @@ public class UiccSlotUtilTest {
when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(mSubscriptionInfoList);
}
@Test
public void getSlotInfos_oneSimSlotDevice_returnTheCorrectSlotInfoList() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSimSlotDeviceActivePsim());
ImmutableList<UiccSlotInfo> testUiccSlotInfos =
UiccSlotUtil.getSlotInfos(mTelephonyManager);
assertThat(testUiccSlotInfos.size()).isEqualTo(1);
}
@Test
public void getSlotInfos_twoSimSlotsDevice_returnTheCorrectSlotInfoList() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActivePsimActiveEsim());
ImmutableList<UiccSlotInfo> testUiccSlotInfos =
UiccSlotUtil.getSlotInfos(mTelephonyManager);
assertThat(testUiccSlotInfos.size()).isEqualTo(2);
}
@Test
public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot0_returnTheCorrectEsimSlot() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
@@ -643,105 +621,7 @@ public class UiccSlotUtilTest {
assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
}
@Test
public void isRemovableSimEnabled_noPsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeRemovableEsimAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActiveRemovableEsimInactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeRemovableEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActivePsimActiveRemovableEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_inactiveRemovableEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceInactiveRemovableEsimActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_twoActiveRemovableEsimsAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceTwoActiveRemovableEsimsInactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_oneActiveOneInactiveRemovableEsimActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceOneActiveOneInactiveRemovableEsimsActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_activePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceActivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_inactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
oneSimSlotDeviceinactivePsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void isRemovableSimEnabled_activeEsimAndActivePsim_returnsTrue() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceActivePsimActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isTrue();
}
@Test
public void isRemovableSimEnabled_activeEsimAndInactivePsim_returnsFalse() {
when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
twoSimSlotsDeviceInactivePsimActiveEsim());
boolean testSlot = UiccSlotUtil.isRemovableSimEnabled(mTelephonyManager);
assertThat(testSlot).isFalse();
}
@Test
public void performSwitchToSlot_setSimSlotMapping() throws UiccSlotsException {
@@ -856,13 +736,6 @@ public class UiccSlotUtilTest {
return slotMap;
}
private List<UiccSlotMapping> createUiccSlotMappingSsModeEsimPort1Active() {
List<UiccSlotMapping> slotMap = new ArrayList<>();
slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 0));
return slotMap;
}
private List<UiccSlotMapping> createUiccSlotMappingPsimAndPort0() {
List<UiccSlotMapping> slotMap = new ArrayList<>();
slotMap.add(new UiccSlotMapping(0, PSIM_PHYSICAL_SLOT, 0));
@@ -915,14 +788,6 @@ public class UiccSlotUtilTest {
return new UiccSlotInfo[]{createUiccSlotInfo(false, true, 0, true)};
}
private UiccSlotInfo[] oneSimSlotDeviceActiveEsim() {
return new UiccSlotInfo[]{createUiccSlotInfo(true, false, 1, true)};
}
private UiccSlotInfo[] oneSimSlotDeviceinactivePsim() {
return new UiccSlotInfo[]{createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActivePsimActiveEsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, 0, true),
@@ -941,61 +806,12 @@ public class UiccSlotUtilTest {
createUiccSlotInfo(true, true, 1, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActiveRemovableEsimInactivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, true, 0, true),
createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceInactiveRemovableEsimActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, true, -1, false),
createUiccSlotInfo(false, true, 0, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceTwoActiveRemovableEsimsInactivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfoForRemovableEsimMep(0, true, 1, true),
createUiccSlotInfo(false, true, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceOneActiveOneInactiveRemovableEsimsActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfoForRemovableEsimMep(1, true, -1, false),
createUiccSlotInfo(false, true, 0, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActiveEsimActivePsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(true, false, 0, true),
createUiccSlotInfo(false, true, 1, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceTwoActiveEsims() {
// device supports MEP, so device can enable two esims.
// If device has psim slot, the UiccSlotInfo of psim always be in UiccSlotInfo[].
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, -1, true),
createUiccSlotInfoForEsimMep(0, true, 1, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceActivePsimInactiveEsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, 0, true),
createUiccSlotInfo(true, false, -1, false)};
}
private UiccSlotInfo[] twoSimSlotsDeviceInactivePsimActiveEsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, 0, false),
createUiccSlotInfo(true, false, 1, true)};
}
private UiccSlotInfo[] twoSimSlotsDeviceNoInsertPsimActiveEsim() {
return new UiccSlotInfo[]{
createUiccSlotInfo(false, true, -1, false),
createUiccSlotInfo(true, false, 1, true)};
}
//ToDo: add more cases.
private UiccSlotInfo createUiccSlotInfo(boolean isEuicc, boolean isRemovable,
@@ -1011,36 +827,4 @@ public class UiccSlotUtilTest {
logicalSlotIdx /* logicalSlotIdx */, isActive /* isActive */))
);
}
private UiccSlotInfo createUiccSlotInfoForEsimMep(int logicalSlotIdx1, boolean isActiveEsim1,
int logicalSlotIdx2, boolean isActiveEsim2) {
return new UiccSlotInfo(
true, /* isEuicc */
"123", /* cardId */
CARD_STATE_INFO_PRESENT, /* cardStateInfo */
true, /* isExtendApduSupported */
false, /* isRemovable */
Arrays.asList(
new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
logicalSlotIdx1 /* logicalSlotIdx */, isActiveEsim1 /* isActive */),
new UiccPortInfo("" /* iccId */, 1 /* portIdx */,
logicalSlotIdx2 /* logicalSlotIdx */,
isActiveEsim2 /* isActive */)));
}
private UiccSlotInfo createUiccSlotInfoForRemovableEsimMep(int logicalSlotIdx1,
boolean isActiveEsim1, int logicalSlotIdx2, boolean isActiveEsim2) {
return new UiccSlotInfo(
true, /* isEuicc */
"123", /* cardId */
CARD_STATE_INFO_PRESENT, /* cardStateInfo */
true, /* isExtendApduSupported */
true, /* isRemovable */
Arrays.asList(
new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
logicalSlotIdx1 /* logicalSlotIdx */, isActiveEsim1 /* isActive */),
new UiccPortInfo("" /* iccId */, 1 /* portIdx */,
logicalSlotIdx2 /* logicalSlotIdx */,
isActiveEsim2 /* isActive */)));
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.ims;
import android.content.Context;
import android.telephony.ims.ImsException;
/**
* Controller class for mock VT status
*/
public class MockVtQueryImsState extends VtQueryImsState {
private Boolean mIsTtyOnVolteEnabled;
private Boolean mIsEnabledOnPlatform;
private Boolean mIsProvisionedOnDevice;
private Boolean mIsEnabledByUser;
private Boolean mIsServiceStateReady;
/**
* Constructor
*
* @param context {@link Context}
* @param subId subscription's id
*/
public MockVtQueryImsState(Context context, int subId) {
super(context, subId);
}
public void setIsTtyOnVolteEnabled(boolean enabled) {
mIsTtyOnVolteEnabled = enabled;
}
@Override
boolean isTtyOnVolteEnabled(int subId) {
if (mIsTtyOnVolteEnabled != null) {
return mIsTtyOnVolteEnabled;
}
return super.isTtyOnVolteEnabled(subId);
}
public void setIsEnabledByPlatform(boolean isEnabled) {
mIsEnabledOnPlatform = isEnabled;
}
@Override
boolean isEnabledByPlatform(int subId) throws InterruptedException, ImsException,
IllegalArgumentException {
if (mIsEnabledOnPlatform != null) {
return mIsEnabledOnPlatform;
}
return super.isEnabledByPlatform(subId);
}
public void setIsProvisionedOnDevice(boolean isProvisioned) {
mIsProvisionedOnDevice = isProvisioned;
}
@Override
boolean isProvisionedOnDevice(int subId) {
if (mIsProvisionedOnDevice != null) {
return mIsProvisionedOnDevice;
}
return super.isProvisionedOnDevice(subId);
}
public void setServiceStateReady(boolean isReady) {
mIsServiceStateReady = isReady;
}
@Override
boolean isServiceStateReady(int subId) throws InterruptedException, ImsException,
IllegalArgumentException {
if (mIsServiceStateReady != null) {
return mIsServiceStateReady;
}
return super.isServiceStateReady(subId);
}
public void setIsEnabledByUser(boolean enabled) {
mIsEnabledByUser = enabled;
}
@Override
boolean isEnabledByUser(int subId) {
if (mIsEnabledByUser != null) {
return mIsEnabledByUser;
}
return super.isEnabledByUser(subId);
}
}

View File

@@ -1,79 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.telephony;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.network.CarrierConfigCache;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class CarrierSettingsVersionPreferenceControllerTest {
@Mock
private CarrierConfigCache mCarrierConfigCache;
private CarrierSettingsVersionPreferenceController mController;
private int mSubscriptionId = 1234;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Context context = spy(ApplicationProvider.getApplicationContext());
CarrierConfigCache.setTestInstance(context, mCarrierConfigCache);
mController = new CarrierSettingsVersionPreferenceController(context, "mock_key");
mController.init(mSubscriptionId);
}
@Test
public void getSummary_nullConfig_noCrash() {
doReturn(null).when(mCarrierConfigCache).getConfigForSubId(mSubscriptionId);
assertThat(mController.getSummary()).isNull();
}
@Test
public void getSummary_nullVersionString_noCrash() {
doReturn(new PersistableBundle()).when(mCarrierConfigCache)
.getConfigForSubId(mSubscriptionId);
assertThat(mController.getSummary()).isNull();
}
@Test
public void getSummary_hasVersionString_correctSummary() {
final PersistableBundle bundle = new PersistableBundle();
bundle.putString(CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING,
"test_version_123");
doReturn(bundle).when(mCarrierConfigCache).getConfigForSubId(mSubscriptionId);
assertThat(mController.getSummary()).isEqualTo("test_version_123");
}
}

View File

@@ -30,7 +30,6 @@ import android.platform.test.flag.junit.SetFlagsRule;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
@@ -70,15 +69,6 @@ public class DefaultSubscriptionControllerTest {
private static final String DISPLAY_NAME_1 = "Sub 1";
private static final String DISPLAY_NAME_2 = "Sub 2";
private static final String DISPLAY_NAME_3 = "Sub 3";
private static final String SUB_MCC_1 = "123";
private static final String SUB_MNC_1 = "456";
private static final String SUB_MCC_2 = "223";
private static final String SUB_MNC_2 = "456";
private static final String SUB_MCC_3 = "323";
private static final String SUB_MNC_3 = "456";
private static final String SUB_COUNTRY_ISO_1 = "Sub 1";
private static final String SUB_COUNTRY_ISO_2 = "Sub 2";
private static final String SUB_COUNTRY_ISO_3 = "Sub 3";
@Mock
private SubscriptionManager mSubMgr;
@@ -133,12 +123,9 @@ public class DefaultSubscriptionControllerTest {
SubscriptionUtil.setActiveSubscriptionsForTesting(null);
}
private SubscriptionInfoEntity setupSubscriptionInfoEntity(
String subId, String displayName, String mcc, String mnc, String countryIso) {
return new SubscriptionInfoEntity(subId, 1, 1, displayName, displayName, 0, mcc, mnc,
countryIso, false, 1, TelephonyManager.DEFAULT_PORT_INDEX, false, null,
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, false, "1234567890",
true, false, true, true, true, true, false);
private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, String displayName) {
return new SubscriptionInfoEntity(subId, 1, false, false, displayName, false, false, true,
true, false);
}
@Test
@@ -151,8 +138,7 @@ public class DefaultSubscriptionControllerTest {
@Test
public void getSummary_singleSub() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mController.displayPreference(mScreen);
@@ -164,10 +150,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void getSummary_twoSubs() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
@@ -180,10 +164,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onPreferenceChange_prefChangedToSub2_callbackCalledCorrectly() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
@@ -197,10 +179,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onPreferenceChange_prefChangedToAlwaysAsk_callbackCalledCorrectly() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
@@ -217,10 +197,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onPreferenceChange_prefBecomesAvailable_onPreferenceChangeCallbackNotNull() {
// Start with only one sub active, so the pref is not available
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
@@ -240,10 +218,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onSubscriptionsChanged_twoSubscriptionsDefaultChanges_selectedEntryGetsUpdated() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
@@ -261,10 +237,8 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onSubscriptionsChanged_goFromTwoSubscriptionsToOne_prefDisappears() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
@@ -287,10 +261,8 @@ public class DefaultSubscriptionControllerTest {
@Test
@UiThreadTest
public void onSubscriptionsChanged_goFromOneSubscriptionToTwo_prefAppears() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mSubscriptionInfoEntityList.add(mSubInfo1);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mController.onActiveSubInfoChanged(mSubscriptionInfoEntityList);
@@ -309,12 +281,9 @@ public class DefaultSubscriptionControllerTest {
@Test
public void onSubscriptionsChanged_goFromTwoToThreeSubscriptions_listGetsUpdated() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1,
SUB_COUNTRY_ISO_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, SUB_MCC_2, SUB_MNC_2,
SUB_COUNTRY_ISO_2);
mSubInfo3 = setupSubscriptionInfoEntity(SUB_ID_3, DISPLAY_NAME_3, SUB_MCC_3, SUB_MNC_3,
SUB_COUNTRY_ISO_3);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2);
mSubInfo3 = setupSubscriptionInfoEntity(SUB_ID_3, DISPLAY_NAME_3);
mController.setDefaultSubscription(Integer.parseInt(mSubInfo1.subId));
mSubscriptionInfoEntityList.add(mSubInfo1);
mSubscriptionInfoEntityList.add(mSubInfo2);

View File

@@ -18,9 +18,6 @@ package com.android.settings.network.telephony;
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.network.telephony.MobileNetworkUtils.getRafFromNetworkType;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.EVDO;
@@ -33,8 +30,6 @@ import static com.android.settings.network.telephony.TelephonyConstants.RadioAcc
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -123,79 +118,6 @@ public class EnabledNetworkModePreferenceControllerTest {
mPreference.setKey(mController.getPreferenceKey());
}
@UiThreadTest
@Test
public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL,
true);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getRoaming()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getRoaming()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_carrierConfigNotReady_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_notWorldPhone_returnAvailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
false);
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@UiThreadTest
@Test
public void getAvailabilityStatus_callStateIsIdle_returnAvailable() {
mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA);
mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_IDLE);
mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertTrue(mPreference.isEnabled());
}
@UiThreadTest
@Test
public void getAvailabilityStatus_duringCalling_returnAvailable() {
mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA);
mController.getTelephonyCallback().onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK);
mController.updateState(mPreference);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
assertFalse(mPreference.isEnabled());
}
@UiThreadTest
@Test
public void updateState_LteWorldPhone_GlobalHasLte() {

View File

@@ -1,75 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.telephony;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class EuiccPreferenceControllerTest {
private static final int SUB_ID = 2;
@Mock private TelephonyManager mTelephonyManager;
private EuiccPreferenceController mController;
private Preference mPreference;
private Context mContext;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
mPreference = new Preference(mContext);
mController = new EuiccPreferenceController(mContext, "euicc");
mController.init(SUB_ID);
mPreference.setKey(mController.getPreferenceKey());
}
@Test
public void handlePreferenceTreeClick_startActivity() {
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mContext).startActivity(captor.capture());
mController.handlePreferenceTreeClick(mPreference);
assertThat(captor.getValue().getAction()).isEqualTo(
EuiccManager.ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS);
}
}

View File

@@ -29,7 +29,6 @@ import android.app.Instrumentation;
import android.content.Context;
import android.os.Looper;
import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -75,8 +74,6 @@ public class MobileDataPreferenceControllerTest {
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private FragmentTransaction mFragmentTransaction;
@Mock
private Lifecycle mLifecycle;
@@ -120,19 +117,15 @@ public class MobileDataPreferenceControllerTest {
}
private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, String displayName,
boolean isOpportunistic, boolean isValid, boolean isActive, boolean isAvailable) {
boolean isOpportunistic, boolean isValid, boolean isActive) {
int id = Integer.parseInt(subId);
return new SubscriptionInfoEntity(subId, id, id,
displayName, displayName, 0, "mcc", "mnc", "countryIso", false, id,
TelephonyManager.DEFAULT_PORT_INDEX, isOpportunistic, null,
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, false,
"1234567890", true, false, isValid, true, isActive, isAvailable, false);
return new SubscriptionInfoEntity(subId, id, false, isOpportunistic, displayName, false,
false, isValid, isActive, false);
}
private MobileNetworkInfoEntity setupMobileNetworkInfoEntity(String subId,
boolean isDatEnabled) {
return new MobileNetworkInfoEntity(subId, false, false, isDatEnabled, false, false, false,
false, false, false, false, false);
return new MobileNetworkInfoEntity(subId, isDatEnabled, false);
}
@Test
@@ -145,7 +138,7 @@ public class MobileDataPreferenceControllerTest {
@Test
public void isDialogNeeded_disableSingleSim_returnFalse() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true);
mNetworkInfo1 = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
doReturn(1).when(mTelephonyManager).getActiveModemCount();
@@ -154,12 +147,12 @@ public class MobileDataPreferenceControllerTest {
@Test
public void isDialogNeeded_enableNonDefaultSimInMultiSimMode_returnTrue() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true);
mNetworkInfo1 = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
doReturn(1).when(mTelephonyManager).getActiveModemCount();
// Ideally, it would be better if we could set the default data subscription to
// SUB_ID_OTHER, and set that as an active subscription id.
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, false, true, true, true);
mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, DISPLAY_NAME_2, false, true, true);
mNetworkInfo1 = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
doReturn(2).when(mTelephonyManager).getActiveModemCount();
@@ -181,7 +174,7 @@ public class MobileDataPreferenceControllerTest {
@Test
public void onPreferenceChange_singleSim_On_shouldEnableData() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true);
mNetworkInfo1 = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
mController.setSubscriptionInfoEntity(mSubInfo1);
mController.setMobileNetworkInfoEntity(mNetworkInfo1);
@@ -195,7 +188,7 @@ public class MobileDataPreferenceControllerTest {
@Test
public void onPreferenceChange_multiSim_On_shouldEnableData() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true);
mNetworkInfo1 = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
mController.setSubscriptionInfoEntity(mSubInfo1);
mController.setMobileNetworkInfoEntity(mNetworkInfo1);
@@ -220,7 +213,7 @@ public class MobileDataPreferenceControllerTest {
@Test
public void updateState_opportunistic_disabled() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, true, true, true);
mController.init(mFragmentManager, SUB_ID, mSubInfo1, mNetworkInfo1);
mController.updateState(mPreference);
@@ -232,7 +225,7 @@ public class MobileDataPreferenceControllerTest {
@Test
public void updateState_notOpportunistic_enabled() {
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true, true);
mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, DISPLAY_NAME_1, false, true, true);
mController.init(mFragmentManager, SUB_ID, mSubInfo1, mNetworkInfo1);
mController.updateState(mPreference);

View File

@@ -16,8 +16,6 @@
package com.android.settings.network.telephony;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA;
@@ -32,7 +30,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -91,43 +88,6 @@ public class PreferredNetworkModePreferenceControllerTest {
mPreference.setKey(mController.getPreferenceKey());
}
@Test
public void getAvailabilityStatus_hideCarrierNetworkSettings_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_worldPhone_returnAvailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL,
false);
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL, true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_hidePreferredNetworkType_returnUnavailable() {
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL,
true);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mServiceState.getRoaming()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
when(mServiceState.getRoaming()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void updateState_updateByNetworkMode() {
// NETWORK_MODE_TDSCDMA_GSM_WCDMA = RAF_TD_SCDMA | GSM | WCDMA

View File

@@ -1,234 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.telephony;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class RoamingPreferenceControllerTest {
private static final int SUB_ID = 2;
@Mock
private FragmentManager mFragmentManager;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private TelephonyManager mInvalidTelephonyManager;
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
private FragmentTransaction mFragmentTransaction;
@Mock
private CarrierConfigManager mCarrierConfigManager;
@Mock
private Lifecycle mLifecycle;
@Mock
private LifecycleOwner mLifecycleOwner;
private LifecycleRegistry mLifecycleRegistry;
private RoamingPreferenceController mController;
private RestrictedSwitchPreference mPreference;
private Context mContext;
private MobileNetworkInfoEntity mMobileNetworkInfoEntity;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mContext = spy(ApplicationProvider.getApplicationContext());
doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
doReturn(mSubscriptionManager).when(mContext).getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
doReturn(mCarrierConfigManager).when(mContext).getSystemService(
Context.CARRIER_CONFIG_SERVICE);
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();
mPreference = spy(new RestrictedSwitchPreference(mContext));
mController = spy(
new RoamingPreferenceController(mContext, "roaming", mLifecycle, mLifecycleOwner,
SUB_ID));
mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
mController.init(mFragmentManager, SUB_ID, mMobileNetworkInfoEntity);
mPreference.setKey(mController.getPreferenceKey());
}
private MobileNetworkInfoEntity setupMobileNetworkInfoEntity(String subId,
boolean isDataRoaming) {
return new MobileNetworkInfoEntity(subId, false, false, true, false, false, false, false,
false, false, false, isDataRoaming);
}
@Test
public void getAvailabilityStatus_validSubId_returnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
AVAILABLE);
}
@Test
public void getAvailabilityStatus_invalidSubId_returnUnsearchable() {
mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
mMobileNetworkInfoEntity);
assertThat(mController.getAvailabilityStatus(
SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(
BasePreferenceController.AVAILABLE_UNSEARCHABLE);
}
@Test
public void isDialogNeeded_roamingDisabledWithoutFlag_returnTrue() {
final PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
assertThat(mController.isDialogNeeded()).isTrue();
}
@Test
public void isDialogNeeded_roamingEnabled_returnFalse() {
mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
assertThat(mController.isDialogNeeded()).isFalse();
}
@Test
@UiThreadTest
public void setChecked_needDialog_showDialog() {
mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
doReturn(null).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
mController.setChecked(true);
verify(mFragmentManager).beginTransaction();
}
@Test
public void updateState_invalidSubId_disabled() {
mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(
String.valueOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID), false);
mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
mMobileNetworkInfoEntity);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void updateState_validSubId_enabled() {
mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void updateState_isNotDisabledByAdmin_shouldInvokeSetEnabled() {
when(mPreference.isDisabledByAdmin()).thenReturn(false);
mController.updateState(mPreference);
verify(mPreference).setEnabled(anyBoolean());
}
@Test
public void updateState_isDisabledByAdmin_shouldNotInvokeSetEnabled() {
when(mPreference.isDisabledByAdmin()).thenReturn(true);
mController.updateState(mPreference);
verify(mPreference, never()).setEnabled(anyBoolean());
}
@Test
public void getAvailabilityStatus_carrierConfigIsNull_shouldReturnAvailable() {
doReturn(null).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_forceHomeNetworkIsFalse_shouldReturnAvailable() {
final PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, false);
doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_forceHomeNetworkIsTrue_shouldReturnConditionallyAvailable() {
final PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, true);
doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
}

View File

@@ -339,6 +339,30 @@ public class SecuritySettingsTest {
assertThat(mPreferenceCombined.isVisible()).isFalse();
}
@Test
public void noFace_isNotIndexable() throws Exception {
when(mFaceManager.isHardwareDetected()).thenReturn(false);
final BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
final List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
final List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
allXmlKeys.removeAll(nonIndexableKeys);
assertThat(allXmlKeys).doesNotContain(SecuritySettings.KEY_FACE_SETTINGS);
}
@Test
public void noFingerprint_isNotIndexable() throws Exception {
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
final BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
final List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
final List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
allXmlKeys.removeAll(nonIndexableKeys);
assertThat(allXmlKeys).doesNotContain(SecuritySettings.KEY_FINGERPRINT_SETTINGS);
}
boolean isFacePrefAvailable(List<AbstractPreferenceController> controllers) {
return controllers.stream().filter(
controller -> controller instanceof FaceStatusPreferenceController

View File

@@ -25,7 +25,6 @@ import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
import com.android.settings.biometrics.fingerprint.FingerprintFeatureProvider;
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.fastpair.FastPairFeatureProvider;
import com.android.settings.connecteddevice.stylus.StylusFeatureProvider;
@@ -82,7 +81,6 @@ public class FakeFeatureFactory extends FeatureFactory {
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
public final FaceFeatureProvider mFaceFeatureProvider;
public final FingerprintFeatureProvider mFingerprintFeatureProvider;
public final BiometricsRepositoryProvider mBiometricsRepositoryProvider;
public PanelFeatureProvider panelFeatureProvider;
public SlicesFeatureProvider slicesFeatureProvider;
@@ -140,7 +138,6 @@ public class FakeFeatureFactory extends FeatureFactory {
mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
mFingerprintFeatureProvider = mock(FingerprintFeatureProvider.class);
mBiometricsRepositoryProvider = mock(BiometricsRepositoryProvider.class);
wifiTrackerLibProvider = mock(WifiTrackerLibProvider.class);
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
@@ -272,11 +269,6 @@ public class FakeFeatureFactory extends FeatureFactory {
return mFingerprintFeatureProvider;
}
@Override
public BiometricsRepositoryProvider getBiometricsRepositoryProvider() {
return mBiometricsRepositoryProvider;
}
@Override
public WifiTrackerLibProvider getWifiTrackerLibProvider() {
return wifiTrackerLibProvider;

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 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.wifi
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.android.settings.core.BasePreferenceController.AVAILABLE
import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE
import com.android.wifitrackerlib.WifiEntry
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
class WepLessSecureWarningControllerTest {
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Spy
private val context: Context = ApplicationProvider.getApplicationContext()
@Mock
private lateinit var mockWifiEntry: WifiEntry
private val controller = WepLessSecureWarningController(context, TEST_KEY)
@Test
fun getAvailabilityStatus_default_conditionallyUnavailable() {
assertThat(controller.availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
}
@Test
fun getAvailabilityStatus_noWepSecurityType_conditionallyUnavailable() {
whenever(mockWifiEntry.securityTypes).thenReturn(listOf(WifiEntry.SECURITY_PSK))
controller.setWifiEntry(mockWifiEntry)
assertThat(controller.availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
}
@Test
fun getAvailabilityStatus_containsWepSecurityType_available() {
whenever(mockWifiEntry.securityTypes).thenReturn(listOf(WifiEntry.SECURITY_WEP))
controller.setWifiEntry(mockWifiEntry)
assertThat(controller.availabilityStatus).isEqualTo(AVAILABLE)
}
private companion object {
const val TEST_KEY = "test_key"
}
}

View File

@@ -20,15 +20,33 @@ import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.wifi.factory.WifiFeatureProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -44,18 +62,36 @@ public class WifiDppConfiguratorActivityTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private UserManager mUserManager;
@Mock
private FragmentManager mFragmentManager;
// Mock, created by FakeFeatureFactory
private WifiFeatureProvider mWifiFeatureProviderMock;
@Spy
private WifiDppConfiguratorActivity mActivity;
@Before
public void setUp() {
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mActivity = new WifiDppConfiguratorActivity();
mActivity.mFragmentManager = mFragmentManager;
doReturn(mContext).when(mActivity).getApplicationContext();
FragmentTransaction mockTransaction = mock(FragmentTransaction.class);
when(mFragmentManager.beginTransaction()).thenReturn(mockTransaction);
when(mockTransaction.replace(anyInt(), any(Fragment.class), anyString()))
.thenReturn(mockTransaction);
FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
mWifiFeatureProviderMock = featureFactory.mWifiFeatureProvider;
}
@Test
@@ -71,4 +107,37 @@ public class WifiDppConfiguratorActivityTest {
assertThat(mActivity.isAddWifiConfigAllowed(mContext)).isFalse();
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_WIFI_SHARING_RUNTIME_FRAGMENT)
public void showQrCodeGeneratorFragment_shouldUseFeatureFactory() {
when(mUserManager.isGuestUser()).thenReturn(false);
when(mWifiFeatureProviderMock.getWifiDppQrCodeGeneratorFragment())
.thenReturn(new WifiDppQrCodeGeneratorFragment());
mActivity.handleIntent(createQrCodeGeneratorIntent());
verify(mWifiFeatureProviderMock).getWifiDppQrCodeGeneratorFragment();
}
@Test
@DisableFlags(Flags.FLAG_ENABLE_WIFI_SHARING_RUNTIME_FRAGMENT)
public void showQrCodeGeneratorFragment_shouldNotUseFeatureFactory() {
when(mUserManager.isGuestUser()).thenReturn(false);
mActivity.handleIntent(createQrCodeGeneratorIntent());
verify(mWifiFeatureProviderMock, never())
.getWifiDppQrCodeGeneratorFragment();
}
private static Intent createQrCodeGeneratorIntent() {
Intent intent = new Intent(
WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WPA");
intent.putExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY, "\\012345678,");
return intent;
}
}

View File

@@ -109,21 +109,21 @@ public class WifiHotspotRepositoryTest {
doReturn(SPEED_6GHZ).when(mSpeedType).getValue();
doReturn(true).when(mWifiManager).is5GHzBandSupported();
doReturn(Arrays.asList(new WifiAvailableChannel(FREQ_5GHZ, OP_MODE_SAP))).when(mWifiManager)
.getUsableChannels(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS, OP_MODE_SAP);
.getAllowedChannels(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS, OP_MODE_SAP);
doReturn(true).when(mWifiManager).is6GHzBandSupported();
doReturn(Arrays.asList(new WifiAvailableChannel(FREQ_6GHZ, OP_MODE_SAP))).when(mWifiManager)
.getUsableChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
.getAllowedChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
mRepository = new WifiHotspotRepository(mContext, mWifiManager, mTetheringManager);
mRepository.mSecurityType = mSecurityType;
mRepository.mSpeedType = mSpeedType;
mRepository.mIsDualBand = true;
mRepository.mBand5g.isUsableChannelsReady = true;
mRepository.mBand5g.isUsableChannelsUnsupported = false;
mRepository.mBand5g.hasUsableChannels = true;
mRepository.mBand6g.isUsableChannelsReady = true;
mRepository.mBand6g.isUsableChannelsUnsupported = false;
mRepository.mBand6g.hasUsableChannels = true;
mRepository.mBand5g.isChannelsReady = true;
mRepository.mBand5g.isChannelsUnsupported = false;
mRepository.mBand5g.hasChannels = true;
mRepository.mBand6g.isChannelsReady = true;
mRepository.mBand6g.isChannelsUnsupported = false;
mRepository.mBand6g.hasChannels = true;
}
@Test
@@ -382,7 +382,7 @@ public class WifiHotspotRepositoryTest {
@Test
public void updateSpeedType_singleBand5gPreferredBut5gUnavailable_get2gSpeedType() {
mRepository.mIsDualBand = false;
mRepository.mBand5g.hasUsableChannels = false;
mRepository.mBand5g.hasChannels = false;
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(WIFI_5GHZ_BAND_PREFERRED).build();
when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
@@ -407,7 +407,7 @@ public class WifiHotspotRepositoryTest {
@Test
public void updateSpeedType_singleBand6gPreferredBut6gUnavailable_get5gSpeedType() {
mRepository.mIsDualBand = false;
mRepository.mBand6g.hasUsableChannels = false;
mRepository.mBand6g.hasChannels = false;
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(WIFI_6GHZ_BAND_PREFERRED).build();
when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
@@ -420,8 +420,8 @@ public class WifiHotspotRepositoryTest {
@Test
public void updateSpeedType_singleBand6gPreferredBut5gAnd6gUnavailable_get2gSpeedType() {
mRepository.mIsDualBand = false;
mRepository.mBand5g.hasUsableChannels = false;
mRepository.mBand6g.hasUsableChannels = false;
mRepository.mBand5g.hasChannels = false;
mRepository.mBand6g.hasChannels = false;
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(WIFI_6GHZ_BAND_PREFERRED).build();
when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
@@ -446,7 +446,7 @@ public class WifiHotspotRepositoryTest {
@Test
public void updateSpeedType_dualBand2gAnd5gBut5gUnavailable_get2gSpeedType() {
mRepository.mIsDualBand = true;
mRepository.mBand5g.hasUsableChannels = false;
mRepository.mBand5g.hasChannels = false;
SoftApConfiguration config = new SoftApConfiguration.Builder()
.setBand(WIFI_5GHZ_BAND_PREFERRED).build();
when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
@@ -562,20 +562,20 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void is5gAvailable_hasUsableChannels_returnTrue() {
public void is5gAvailable_hasChannels_returnTrue() {
mRepository.mIs5gBandSupported = true;
// Reset m5gBand to trigger an update
mRepository.mBand5g.isUsableChannelsReady = false;
mRepository.mBand5g.isChannelsReady = false;
assertThat(mRepository.is5gAvailable()).isTrue();
}
@Test
public void is5gAvailable_noUsableChannels_returnFalse() {
public void is5gAvailable_noChannels_returnFalse() {
mRepository.mIs5gBandSupported = true;
// Reset m5gBand to trigger an update
mRepository.mBand5g.isUsableChannelsReady = false;
when(mWifiManager.getUsableChannels(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS, OP_MODE_SAP))
mRepository.mBand5g.isChannelsReady = false;
when(mWifiManager.getAllowedChannels(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS, OP_MODE_SAP))
.thenReturn(null);
assertThat(mRepository.is5gAvailable()).isFalse();
@@ -585,7 +585,7 @@ public class WifiHotspotRepositoryTest {
@UiThreadTest
public void get5gAvailable_shouldNotReturnNull() {
// Reset m5gBand to trigger an update
mRepository.mBand5g.isUsableChannelsReady = false;
mRepository.mBand5g.isChannelsReady = false;
assertThat(mRepository.get5gAvailable()).isNotNull();
}
@@ -606,20 +606,20 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void is6gAvailable_hasUsableChannels_returnTrue() {
public void is6gAvailable_hasChannels_returnTrue() {
mRepository.mIs6gBandSupported = true;
// Reset m6gBand to trigger an update
mRepository.mBand6g.isUsableChannelsReady = false;
mRepository.mBand6g.isChannelsReady = false;
assertThat(mRepository.is6gAvailable()).isTrue();
}
@Test
public void is6gAvailable_noUsableChannels_returnFalse() {
public void is6gAvailable_noChannels_returnFalse() {
mRepository.mIs6gBandSupported = true;
// Reset m6gBand to trigger an update
mRepository.mBand6g.isUsableChannelsReady = false;
when(mWifiManager.getUsableChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP))
mRepository.mBand6g.isChannelsReady = false;
when(mWifiManager.getAllowedChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP))
.thenReturn(null);
assertThat(mRepository.is6gAvailable()).isFalse();
@@ -658,33 +658,33 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void isChannelAvailable_throwIllegalArgumentException_hasUsableChannelsFalse() {
public void isChannelAvailable_throwIllegalArgumentException_hasChannelsFalse() {
doThrow(IllegalArgumentException.class).when(mWifiManager)
.getUsableChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
.getAllowedChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
mRepository.isChannelAvailable(mRepository.mBand6g);
assertThat(mRepository.mBand6g.hasUsableChannels).isFalse();
assertThat(mRepository.mBand6g.isUsableChannelsUnsupported).isTrue();
assertThat(mRepository.mBand6g.hasChannels).isFalse();
assertThat(mRepository.mBand6g.isChannelsUnsupported).isTrue();
}
@Test
public void isChannelAvailable_throwUnsupportedOperationException_hasUsableChannelsFalse() {
public void isChannelAvailable_throwUnsupportedOperationException_hasChannelsFalse() {
doThrow(UnsupportedOperationException.class).when(mWifiManager)
.getUsableChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
.getAllowedChannels(WifiScanner.WIFI_BAND_6_GHZ, OP_MODE_SAP);
mRepository.isChannelAvailable(mRepository.mBand6g);
assertThat(mRepository.mBand6g.hasUsableChannels).isFalse();
assertThat(mRepository.mBand6g.isUsableChannelsUnsupported).isTrue();
assertThat(mRepository.mBand6g.hasChannels).isFalse();
assertThat(mRepository.mBand6g.isChannelsUnsupported).isTrue();
}
@Test
public void isChannelAvailable_noExceptionAndHasUsableChannels_hasUsableChannelsTrue() {
public void isChannelAvailable_noExceptionAndHasChannels_hasChannelsTrue() {
mRepository.isChannelAvailable(mRepository.mBand6g);
assertThat(mRepository.mBand6g.hasUsableChannels).isTrue();
assertThat(mRepository.mBand6g.isUsableChannelsUnsupported).isFalse();
assertThat(mRepository.mBand6g.hasChannels).isTrue();
assertThat(mRepository.mBand6g.isChannelsUnsupported).isFalse();
}
@Test
@@ -744,9 +744,9 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void updateCapabilityChanged_band5gUsableChannelsUnsupported_update5gAvailable() {
public void updateCapabilityChanged_band5gChannelsUnsupported_update5gAvailable() {
mRepository = spy(new WifiHotspotRepository(mContext, mWifiManager, mTetheringManager));
mRepository.mBand5g.isUsableChannelsUnsupported = true;
mRepository.mBand5g.isChannelsUnsupported = true;
mRepository.updateCapabilityChanged();
@@ -755,9 +755,9 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void updateCapabilityChanged_band6gUsableChannelsUnsupported_update5gAvailable() {
public void updateCapabilityChanged_band6gChannelsUnsupported_update5gAvailable() {
mRepository = spy(new WifiHotspotRepository(mContext, mWifiManager, mTetheringManager));
mRepository.mBand6g.isUsableChannelsUnsupported = true;
mRepository.mBand6g.isChannelsUnsupported = true;
mRepository.updateCapabilityChanged();
@@ -766,18 +766,18 @@ public class WifiHotspotRepositoryTest {
}
@Test
public void isAvailable_isUsableChannelsUnsupportedFalse_returnHasUsableChannels() {
mRepository.mBand6g.isUsableChannelsUnsupported = false;
mRepository.mBand6g.hasUsableChannels = false;
public void isAvailable_isChannelsUnsupportedFalse_returnHasChannels() {
mRepository.mBand6g.isChannelsUnsupported = false;
mRepository.mBand6g.hasChannels = false;
mRepository.mBand6g.hasCapability = true;
assertThat(mRepository.mBand6g.isAvailable()).isFalse();
}
@Test
public void isAvailable_isUsableChannelsUnsupportedTrue_returnHasCapability() {
mRepository.mBand6g.isUsableChannelsUnsupported = true;
mRepository.mBand6g.hasUsableChannels = false;
public void isAvailable_isChannelsUnsupportedTrue_returnHasCapability() {
mRepository.mBand6g.isChannelsUnsupported = true;
mRepository.mBand6g.hasChannels = false;
mRepository.mBand6g.hasCapability = true;
assertThat(mRepository.mBand6g.isAvailable()).isTrue();