Merge 10952656

Merged-In: Ib02ae9caef06a46938947806dac8aabb1fa12d94
Change-Id: Ib1f728fef6241ddd7a2ce1522093f4a62a4a9d81
This commit is contained in:
Xin Li
2023-10-18 15:05:14 -07:00
698 changed files with 37975 additions and 20889 deletions

View File

@@ -0,0 +1,309 @@
/*
* 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.applications.appcompat;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
import static com.android.settings.applications.appcompat.UserAspectRatioManager.KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN;
import static com.android.settings.applications.appcompat.UserAspectRatioManager.KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.platform.test.rule.DeviceTypeRule;
import android.platform.test.rule.FoldableOnly;
import android.platform.test.rule.LargeScreenOnly;
import android.platform.test.rule.TabletOnly;
import android.provider.DeviceConfig;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.R;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.util.List;
/**
* To run this test: atest SettingsUnitTests:UserAspectRatioManagerTest
*/
@RunWith(AndroidJUnit4.class)
@LargeScreenOnly
public class UserAspectRatioManagerTest {
private Context mContext;
private Resources mResources;
private UserAspectRatioManager mUtils;
private String mOriginalSettingsFlag;
private String mOriginalFullscreenFlag;
private String mPackageName = "com.test.mypackage";
private LauncherApps mLauncherApps;
private List<LauncherActivityInfo> mLauncherActivities;
@Rule
public TestRule mDeviceTypeRule = new DeviceTypeRule();
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
mLauncherApps = mock(LauncherApps.class);
mLauncherActivities = mock(List.class);
mUtils = new UserAspectRatioManager(mContext) {
@Override
LauncherApps getLauncherApps() {
return mLauncherApps;
}
};
when(mContext.getResources()).thenReturn(mResources);
doReturn(mLauncherActivities).when(mLauncherApps).getActivityList(anyString(), any());
mOriginalSettingsFlag = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS);
setAspectRatioSettingsBuildTimeFlagEnabled(true);
setAspectRatioSettingsDeviceConfigEnabled("true" /* enabled */, false /* makeDefault */);
mOriginalFullscreenFlag = DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN);
setAspectRatioFullscreenBuildTimeFlagEnabled(true);
setAspectRatioFullscreenDeviceConfigEnabled("true" /* enabled */, false /* makeDefault */);
}
@After
public void tearDown() {
setAspectRatioSettingsDeviceConfigEnabled(mOriginalSettingsFlag, true /* makeDefault */);
setAspectRatioFullscreenDeviceConfigEnabled(mOriginalFullscreenFlag,
true /* makeDefault */);
}
@Test
public void testCanDisplayAspectRatioUi() {
final ApplicationInfo canDisplay = new ApplicationInfo();
canDisplay.packageName = "com.app.candisplay";
doReturn(false).when(mLauncherActivities).isEmpty();
assertTrue(mUtils.canDisplayAspectRatioUi(canDisplay));
final ApplicationInfo noLauncherEntry = new ApplicationInfo();
noLauncherEntry.packageName = "com.app.nolauncherentry";
doReturn(true).when(mLauncherActivities).isEmpty();
assertFalse(mUtils.canDisplayAspectRatioUi(noLauncherEntry));
}
@Test
public void testCanDisplayAspectRatioUi_hasLauncher_propertyFalse_returnFalse()
throws PackageManager.NameNotFoundException {
mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, false);
doReturn(true).when(mLauncherActivities).isEmpty();
final ApplicationInfo canDisplay = new ApplicationInfo();
canDisplay.packageName = mPackageName;
assertFalse(mUtils.canDisplayAspectRatioUi(canDisplay));
}
@Test
public void testCanDisplayAspectRatioUi_noLauncher_propertyTrue_returnFalse()
throws PackageManager.NameNotFoundException {
mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, true);
doReturn(true).when(mLauncherActivities).isEmpty();
final ApplicationInfo noLauncherEntry = new ApplicationInfo();
noLauncherEntry.packageName = mPackageName;
assertFalse(mUtils.canDisplayAspectRatioUi(noLauncherEntry));
}
@Test
public void testIsFeatureEnabled() {
assertTrue(UserAspectRatioManager.isFeatureEnabled(mContext));
}
@Test
public void testIsFeatureEnabled_disabledBuildTimeFlag_returnFalse() {
setAspectRatioSettingsBuildTimeFlagEnabled(false);
assertFalse(UserAspectRatioManager.isFeatureEnabled(mContext));
}
@Test
public void testIsFeatureEnabled_disabledRuntimeFlag_returnFalse() {
setAspectRatioSettingsDeviceConfigEnabled("false" /* enabled */, false /* makeDefault */);
assertFalse(UserAspectRatioManager.isFeatureEnabled(mContext));
}
@Test
public void testIsFullscreenOptionEnabled() {
assertTrue(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testIsFullscreenOptionEnabled_settingsDisabled_returnFalse() {
setAspectRatioFullscreenBuildTimeFlagEnabled(false);
assertFalse(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testIsFullscreenOptionEnabled_disabledBuildTimeFlag_returnFalse() {
setAspectRatioFullscreenBuildTimeFlagEnabled(false);
assertFalse(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testIsFullscreenOptionEnabled_disabledRuntimeFlag_returnFalse() {
setAspectRatioFullscreenDeviceConfigEnabled("false" /* enabled */, false /*makeDefault */);
assertFalse(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testIsFullscreenOptionEnabled_propertyFalse_returnsFalse()
throws PackageManager.NameNotFoundException {
mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE, false);
assertFalse(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testIsFullscreenOptionEnabled_propertyTrue_configDisabled_returnsFalse()
throws PackageManager.NameNotFoundException {
mockProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE, true);
setAspectRatioFullscreenDeviceConfigEnabled("false" /* enabled */, false /*makeDefault */);
assertFalse(mUtils.isFullscreenOptionEnabled(mPackageName));
}
@Test
public void testHasAspectRatioOption_fullscreen() {
assertTrue(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mPackageName));
assertTrue(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
mPackageName));
// Only fullscreen option should be disabled
when(mUtils.isFullscreenOptionEnabled(mPackageName)).thenReturn(false);
assertFalse(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mPackageName));
assertTrue(mUtils.hasAspectRatioOption(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
mPackageName));
}
@Test
@FoldableOnly
public void testGetUserMinAspectRatioEntry_Foldable() {
// R.string.user_aspect_ratio_app_default
final String appDefault = ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_app_default");
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_UNSET, mPackageName))
.isEqualTo(appDefault);
// should always return default if value does not correspond to anything
assertThat(mUtils.getUserMinAspectRatioEntry(-1, mPackageName))
.isEqualTo(appDefault);
// R.string.user_aspect_ratio_half_screen
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
mPackageName)).isEqualTo(ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_half_screen"));
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mPackageName)).isEqualTo(ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_fullscreen"));
}
@Test
@TabletOnly
public void testGetUserMinAspectRatioEntry_Tablet() {
// R.string.user_aspect_ratio_app_default
final String appDefault = ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_app_default");
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_UNSET, mPackageName))
.isEqualTo(appDefault);
// should always return default if value does not correspond to anything
assertThat(mUtils.getUserMinAspectRatioEntry(-1, mPackageName))
.isEqualTo(appDefault);
// R.string.user_aspect_ratio_half_screen
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_SPLIT_SCREEN,
mPackageName)).isEqualTo(ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_half_screen"));
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_16_9, mPackageName))
.isEqualTo(ResourcesUtils.getResourcesString(mContext, "user_aspect_ratio_16_9"));
// R.string.user_aspect_ratio_fullscreen
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mPackageName)).isEqualTo(ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_fullscreen"));
}
@Test
public void testGetUserMinAspectRatioEntry_fullscreenDisabled_shouldReturnDefault() {
setAspectRatioFullscreenBuildTimeFlagEnabled(false);
assertThat(mUtils.getUserMinAspectRatioEntry(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mPackageName)).isEqualTo(ResourcesUtils.getResourcesString(mContext,
"user_aspect_ratio_app_default"));
}
private void mockProperty(String propertyName, boolean value)
throws PackageManager.NameNotFoundException {
PackageManager.Property prop = new PackageManager.Property(
propertyName, value, mPackageName, "" /* className */);
PackageManager pm = mock(PackageManager.class);
when(mContext.getPackageManager()).thenReturn(pm);
when(pm.getProperty(propertyName, mPackageName)).thenReturn(prop);
}
private void setAspectRatioSettingsBuildTimeFlagEnabled(boolean enabled) {
when(mResources.getBoolean(R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled))
.thenReturn(enabled);
}
private void setAspectRatioSettingsDeviceConfigEnabled(String enabled, boolean makeDefault) {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, enabled, makeDefault);
}
private void setAspectRatioFullscreenBuildTimeFlagEnabled(boolean enabled) {
when(mResources.getBoolean(R.bool.config_appCompatUserAppAspectRatioFullscreenIsEnabled))
.thenReturn(enabled);
}
private void setAspectRatioFullscreenDeviceConfigEnabled(String enabled, boolean makeDefault) {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, enabled, makeDefault);
}
}

View File

@@ -379,7 +379,7 @@ public class FingerprintEnrollProgressViewModelTest {
// Notify acquire message
final int value = 33;
mCallbackWrapper.mValue.onPointerDown(value);
mCallbackWrapper.mValue.onUdfpsPointerDown(value);
assertThat(liveData.getValue()).isEqualTo(value);
}
@@ -397,7 +397,7 @@ public class FingerprintEnrollProgressViewModelTest {
// Notify acquire message
final int value = 44;
mCallbackWrapper.mValue.onPointerUp(value);
mCallbackWrapper.mValue.onUdfpsPointerUp(value);
assertThat(liveData.getValue()).isEqualTo(value);
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.bluetooth;
import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -24,8 +26,8 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -42,20 +44,20 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.bluetooth.BlockingPrefWithSliceController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class BlockingPrefWithSliceControllerTest {
private static final String KEY = "bt_device_slice_category";
private static final String TEST_URI_AUTHORITY = "com.android.authority.test";
private static final String TEST_URI_AUTHORITY = "com.android.settings";
private static final String TEST_EXTRA_INTENT = "EXTRA_INTENT";
private static final String TEST_EXTRA_PENDING_INTENT = "EXTRA_PENDING_INTENT";
private static final String TEST_INTENT_ACTION = "test";
@@ -71,6 +73,8 @@ public class BlockingPrefWithSliceControllerTest {
private LiveData<Slice> mLiveData;
@Mock
private PreferenceCategory mPreferenceCategory;
@Captor
ArgumentCaptor<Preference> mPreferenceArgumentCaptor;
private Context mContext;
private BlockingPrefWithSliceController mController;
@@ -130,6 +134,14 @@ public class BlockingPrefWithSliceControllerTest {
verify(mController.mPreferenceCategory).addPreference(any());
}
@Test
public void onChanged_sliceWithoutValidIntent_makePreferenceUnselectable() {
mController.onChanged(buildTestSlice());
verify(mController.mPreferenceCategory).addPreference(mPreferenceArgumentCaptor.capture());
assertThat(mPreferenceArgumentCaptor.getValue().isSelectable()).isFalse();
}
private Slice buildTestSlice() {
Uri uri =
new Uri.Builder()
@@ -141,7 +153,7 @@ public class BlockingPrefWithSliceControllerTest {
IconCompat icon = mock(IconCompat.class);
listBuilder.addRow(
new RowBuilder()
.setTitleItem(icon, ListBuilder.ICON_IMAGE)
.setTitleItem(icon, ICON_IMAGE)
.setTitle(TEST_SLICE_TITLE)
.setSubtitle(TEST_SLICE_SUBTITLE)
.setPrimaryAction(
@@ -153,7 +165,7 @@ public class BlockingPrefWithSliceControllerTest {
PendingIntent.FLAG_UPDATE_CURRENT
| PendingIntent.FLAG_IMMUTABLE),
icon,
ListBuilder.ICON_IMAGE,
ICON_IMAGE,
"")));
return listBuilder.build();
}

View File

@@ -0,0 +1,82 @@
/*
* 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.fingerprint2.domain.interactor
import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
/** Fake to be used by other classes to easily fake the FingerprintManager implementation. */
class FakeFingerprintManagerInteractor : FingerprintManagerInteractor {
var enrollableFingerprints: Int = 5
var enrolledFingerprintsInternal: MutableList<FingerprintViewModel> = mutableListOf()
var challengeToGenerate: Pair<Long, ByteArray> = Pair(-1L, byteArrayOf())
var authenticateAttempt = FingerprintAuthAttemptViewModel.Success(1)
var pressToAuthEnabled = true
var sensorProps =
listOf(
FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
emptyList() /* ComponentInfoInternal */,
TYPE_POWER_BUTTON,
true /* resetLockoutRequiresHardwareAuthToken */
)
)
override suspend fun authenticate(): FingerprintAuthAttemptViewModel {
return authenticateAttempt
}
override suspend fun generateChallenge(gateKeeperPasswordHandle: Long): Pair<Long, ByteArray> {
return challengeToGenerate
}
override val enrolledFingerprints: Flow<List<FingerprintViewModel>> = flow {
emit(enrolledFingerprintsInternal)
}
override fun canEnrollFingerprints(numFingerprints: Int): Flow<Boolean> = flow {
emit(numFingerprints < enrollableFingerprints)
}
override val maxEnrollableFingerprints: Flow<Int> = flow { emit(enrollableFingerprints) }
override suspend fun removeFingerprint(fp: FingerprintViewModel): Boolean {
return enrolledFingerprintsInternal.remove(fp)
}
override suspend fun renameFingerprint(fp: FingerprintViewModel, newName: String) {}
override suspend fun hasSideFps(): Boolean {
return sensorProps.any { it.isAnySidefpsType }
}
override suspend fun pressToAuthEnabled(): Boolean {
return pressToAuthEnabled
}
override suspend fun sensorPropertiesInternal(): List<FingerprintSensorPropertiesInternal> =
sensorProps
}

View File

@@ -0,0 +1,287 @@
/*
* 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.fingerprint2.domain.interactor
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.hardware.fingerprint.Fingerprint
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintManager.CryptoObject
import android.hardware.fingerprint.FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT
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.domain.interactor.FingerprintManagerInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
import com.android.settings.password.ChooseLockSettingsHelper
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.flow.last
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
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.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.eq
import org.mockito.ArgumentMatchers.nullable
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class FingerprintManagerInteractorTest {
@JvmField @Rule var rule = MockitoJUnit.rule()
private lateinit var underTest: FingerprintManagerInteractor
private var context: Context = ApplicationProvider.getApplicationContext()
private var backgroundDispatcher = StandardTestDispatcher()
@Mock private lateinit var fingerprintManager: FingerprintManager
@Mock private lateinit var gateKeeperPasswordProvider: GatekeeperPasswordProvider
private var testScope = TestScope(backgroundDispatcher)
private var pressToAuthProvider = { true }
@Before
fun setup() {
underTest =
FingerprintManagerInteractorImpl(
context,
backgroundDispatcher,
fingerprintManager,
gateKeeperPasswordProvider,
pressToAuthProvider,
)
}
@Test
fun testEmptyFingerprints() =
testScope.runTest {
Mockito.`when`(fingerprintManager.getEnrolledFingerprints(Mockito.anyInt()))
.thenReturn(emptyList())
val emptyFingerprintList: List<Fingerprint> = emptyList()
assertThat(underTest.enrolledFingerprints.last()).isEqualTo(emptyFingerprintList)
}
@Test
fun testOneFingerprint() =
testScope.runTest {
val expected = Fingerprint("Finger 1,", 2, 3L)
val fingerprintList: List<Fingerprint> = listOf(expected)
Mockito.`when`(fingerprintManager.getEnrolledFingerprints(Mockito.anyInt()))
.thenReturn(fingerprintList)
val list = underTest.enrolledFingerprints.last()
assertThat(list.size).isEqualTo(fingerprintList.size)
val actual = list[0]
assertThat(actual.name).isEqualTo(expected.name)
assertThat(actual.fingerId).isEqualTo(expected.biometricId)
assertThat(actual.deviceId).isEqualTo(expected.deviceId)
}
@Test
fun testCanEnrollFingerprint() =
testScope.runTest {
val mockContext = Mockito.mock(Context::class.java)
val resources = Mockito.mock(Resources::class.java)
Mockito.`when`(mockContext.resources).thenReturn(resources)
Mockito.`when`(resources.getInteger(anyInt())).thenReturn(3)
underTest =
FingerprintManagerInteractorImpl(
mockContext,
backgroundDispatcher,
fingerprintManager,
gateKeeperPasswordProvider,
pressToAuthProvider,
)
assertThat(underTest.canEnrollFingerprints(2).last()).isTrue()
assertThat(underTest.canEnrollFingerprints(3).last()).isFalse()
}
@Test
fun testGenerateChallenge() =
testScope.runTest {
val byteArray = byteArrayOf(5, 3, 2)
val challenge = 100L
val intent = Intent()
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, challenge)
Mockito.`when`(
gateKeeperPasswordProvider.requestGatekeeperHat(
any(Intent::class.java),
anyLong(),
anyInt()
)
)
.thenReturn(byteArray)
val generateChallengeCallback: ArgumentCaptor<FingerprintManager.GenerateChallengeCallback> =
ArgumentCaptor.forClass(FingerprintManager.GenerateChallengeCallback::class.java)
var result: Pair<Long, ByteArray?>? = null
val job = testScope.launch { result = underTest.generateChallenge(1L) }
runCurrent()
Mockito.verify(fingerprintManager)
.generateChallenge(anyInt(), capture(generateChallengeCallback))
generateChallengeCallback.value.onChallengeGenerated(1, 2, challenge)
runCurrent()
job.cancelAndJoin()
assertThat(result?.first).isEqualTo(challenge)
assertThat(result?.second).isEqualTo(byteArray)
}
@Test
fun testRemoveFingerprint_succeeds() =
testScope.runTest {
val fingerprintViewModelToRemove = FingerprintViewModel("Finger 2", 1, 2L)
val fingerprintToRemove = Fingerprint("Finger 2", 1, 2L)
val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> =
ArgumentCaptor.forClass(FingerprintManager.RemovalCallback::class.java)
var result: Boolean? = null
val job =
testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) }
runCurrent()
Mockito.verify(fingerprintManager)
.remove(any(Fingerprint::class.java), anyInt(), capture(removalCallback))
removalCallback.value.onRemovalSucceeded(fingerprintToRemove, 1)
runCurrent()
job.cancelAndJoin()
assertThat(result).isTrue()
}
@Test
fun testRemoveFingerprint_fails() =
testScope.runTest {
val fingerprintViewModelToRemove = FingerprintViewModel("Finger 2", 1, 2L)
val fingerprintToRemove = Fingerprint("Finger 2", 1, 2L)
val removalCallback: ArgumentCaptor<FingerprintManager.RemovalCallback> =
ArgumentCaptor.forClass(FingerprintManager.RemovalCallback::class.java)
var result: Boolean? = null
val job =
testScope.launch { result = underTest.removeFingerprint(fingerprintViewModelToRemove) }
runCurrent()
Mockito.verify(fingerprintManager)
.remove(any(Fingerprint::class.java), anyInt(), capture(removalCallback))
removalCallback.value.onRemovalError(
fingerprintToRemove,
100,
"Oh no, we couldn't find that one"
)
runCurrent()
job.cancelAndJoin()
assertThat(result).isFalse()
}
@Test
fun testRenameFingerprint_succeeds() =
testScope.runTest {
val fingerprintToRename = FingerprintViewModel("Finger 2", 1, 2L)
underTest.renameFingerprint(fingerprintToRename, "Woo")
Mockito.verify(fingerprintManager)
.rename(eq(fingerprintToRename.fingerId), anyInt(), safeEq("Woo"))
}
@Test
fun testAuth_succeeds() =
testScope.runTest {
val fingerprint = Fingerprint("Woooo", 100, 101L)
var result: FingerprintAuthAttemptViewModel? = null
val job = launch { result = underTest.authenticate() }
val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> =
ArgumentCaptor.forClass(FingerprintManager.AuthenticationCallback::class.java)
runCurrent()
Mockito.verify(fingerprintManager)
.authenticate(
nullable(CryptoObject::class.java),
any(CancellationSignal::class.java),
capture(authCallback),
nullable(Handler::class.java),
anyInt()
)
authCallback.value.onAuthenticationSucceeded(
FingerprintManager.AuthenticationResult(null, fingerprint, 1, false)
)
runCurrent()
job.cancelAndJoin()
assertThat(result).isEqualTo(FingerprintAuthAttemptViewModel.Success(fingerprint.biometricId))
}
@Test
fun testAuth_lockout() =
testScope.runTest {
var result: FingerprintAuthAttemptViewModel? = null
val job = launch { result = underTest.authenticate() }
val authCallback: ArgumentCaptor<FingerprintManager.AuthenticationCallback> =
ArgumentCaptor.forClass(FingerprintManager.AuthenticationCallback::class.java)
runCurrent()
Mockito.verify(fingerprintManager)
.authenticate(
nullable(CryptoObject::class.java),
any(CancellationSignal::class.java),
capture(authCallback),
nullable(Handler::class.java),
anyInt()
)
authCallback.value.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "Lockout!!")
runCurrent()
job.cancelAndJoin()
assertThat(result)
.isEqualTo(
FingerprintAuthAttemptViewModel.Error(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "Lockout!!")
)
}
private fun <T : Any> safeEq(value: T): T = eq(value) ?: value
private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
}

View File

@@ -0,0 +1,275 @@
/*
* 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.fingerprint2.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.EnrollFirstFingerprint
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettings
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FinishSettingsWithResult
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.LaunchConfirmDeviceCredential
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.NextStepViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.ShowSettings
import com.android.settings.fingerprint2.domain.interactor.FakeFingerprintManagerInteractor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
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.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class FingerprintSettingsNavigationViewModelTest {
@JvmField @Rule var rule = MockitoJUnit.rule()
@get:Rule val instantTaskRule = InstantTaskExecutorRule()
private lateinit var underTest: FingerprintSettingsNavigationViewModel
private val defaultUserId = 0
private var backgroundDispatcher = StandardTestDispatcher()
private var testScope = TestScope(backgroundDispatcher)
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
@Before
fun setup() {
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
backgroundDispatcher = StandardTestDispatcher()
testScope = TestScope(backgroundDispatcher)
Dispatchers.setMain(backgroundDispatcher)
underTest =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
null,
null,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun testNoGateKeeper_launchesConfirmDeviceCredential() =
testScope.runTest {
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
runCurrent()
assertThat(nextStep).isEqualTo(LaunchConfirmDeviceCredential(defaultUserId))
job.cancel()
}
@Test
fun testConfirmDevice_fails() =
testScope.runTest {
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(false, null)
runCurrent()
assertThat(nextStep).isInstanceOf(FinishSettings::class.java)
job.cancel()
}
@Test
fun confirmDeviceSuccess_noGateKeeper() =
testScope.runTest {
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, null)
runCurrent()
assertThat(nextStep).isInstanceOf(FinishSettings::class.java)
job.cancel()
}
@Test
fun confirmDeviceSuccess_launchesEnrollment_ifNoPreviousEnrollments() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
runCurrent()
assertThat(nextStep).isEqualTo(EnrollFirstFingerprint(defaultUserId, 10L, null, null))
job.cancel()
}
@Test
fun firstEnrollment_fails() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollFirstFailure("We failed!!")
runCurrent()
assertThat(nextStep).isInstanceOf(FinishSettings::class.java)
job.cancel()
}
@Test
fun firstEnrollment_failsWithReason() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
val failStr = "We failed!!"
val failReason = 101
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollFirstFailure(failStr, failReason)
runCurrent()
assertThat(nextStep).isEqualTo(FinishSettingsWithResult(failReason, failStr))
job.cancel()
}
@Test
fun firstEnrollmentSucceeds_noToken() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollFirst(null, null)
runCurrent()
assertThat(nextStep).isEqualTo(FinishSettings("Error, empty token"))
job.cancel()
}
@Test
fun firstEnrollmentSucceeds_noKeyChallenge() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
val byteArray = ByteArray(1) { 3 }
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollFirst(byteArray, null)
runCurrent()
assertThat(nextStep).isEqualTo(FinishSettings("Error, empty keyChallenge"))
job.cancel()
}
@Test
fun firstEnrollment_succeeds() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf()
var nextStep: NextStepViewModel? = null
val job = testScope.launch { underTest.nextStep.collect { nextStep = it } }
val byteArray = ByteArray(1) { 3 }
val keyChallenge = 89L
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollFirst(byteArray, keyChallenge)
runCurrent()
assertThat(nextStep).isEqualTo(ShowSettings)
job.cancel()
}
@Test
fun enrollAdditionalFingerprints_fails() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
fakeFingerprintManagerInteractor.challengeToGenerate = Pair(4L, byteArrayOf(3, 3, 1))
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
runCurrent()
underTest.onEnrollAdditionalFailure()
runCurrent()
assertThat(nextStep).isInstanceOf(FinishSettings::class.java)
job.cancel()
}
@Test
fun enrollAdditional_success() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
underTest.onEnrollSuccess()
runCurrent()
assertThat(nextStep).isEqualTo(ShowSettings)
job.cancel()
}
@Test
fun confirmDeviceCredential_withEnrolledFingerprint_showsSettings() =
testScope.runTest {
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
fakeFingerprintManagerInteractor.challengeToGenerate = Pair(10L, byteArrayOf(1, 2, 3))
var nextStep: NextStepViewModel? = null
val job = launch { underTest.nextStep.collect { nextStep = it } }
underTest.onConfirmDevice(true, 10L)
runCurrent()
assertThat(nextStep).isEqualTo(ShowSettings)
job.cancel()
}
}

View File

@@ -0,0 +1,247 @@
/*
* 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.fingerprint2.viewmodel
import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintAuthAttemptViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintSettingsViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.FingerprintViewModel
import com.android.settings.biometrics.fingerprint2.ui.viewmodel.PreferenceViewModel
import com.android.settings.fingerprint2.domain.interactor.FakeFingerprintManagerInteractor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
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.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class FingerprintSettingsViewModelTest {
@JvmField @Rule var rule = MockitoJUnit.rule()
@get:Rule val instantTaskRule = InstantTaskExecutorRule()
private lateinit var underTest: FingerprintSettingsViewModel
private lateinit var navigationViewModel: FingerprintSettingsNavigationViewModel
private val defaultUserId = 0
private var backgroundDispatcher = StandardTestDispatcher()
private var testScope = TestScope(backgroundDispatcher)
private lateinit var fakeFingerprintManagerInteractor: FakeFingerprintManagerInteractor
@Before
fun setup() {
fakeFingerprintManagerInteractor = FakeFingerprintManagerInteractor()
backgroundDispatcher = StandardTestDispatcher()
testScope = TestScope(backgroundDispatcher)
Dispatchers.setMain(backgroundDispatcher)
navigationViewModel =
FingerprintSettingsNavigationViewModel.FingerprintSettingsNavigationModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
null,
null,
)
.create(FingerprintSettingsNavigationViewModel::class.java)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun authenticate_DoesNotRun_ifOptical() =
testScope.runTest {
fakeFingerprintManagerInteractor.sensorProps =
listOf(
FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
emptyList() /* ComponentInfoInternal */,
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */
)
)
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
var authAttempt: FingerprintAuthAttemptViewModel? = null
val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
underTest.shouldAuthenticate(true)
// Ensure we are showing settings
navigationViewModel.onConfirmDevice(true, 10L)
runCurrent()
advanceTimeBy(400)
assertThat(authAttempt).isNull()
job.cancel()
}
@Test
fun authenticate_DoesNotRun_ifUltrasonic() =
testScope.runTest {
fakeFingerprintManagerInteractor.sensorProps =
listOf(
FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
emptyList() /* ComponentInfoInternal */,
FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC,
true /* resetLockoutRequiresHardwareAuthToken */
)
)
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
var authAttempt: FingerprintAuthAttemptViewModel? = null
val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
underTest.shouldAuthenticate(true)
navigationViewModel.onConfirmDevice(true, 10L)
advanceTimeBy(400)
runCurrent()
assertThat(authAttempt).isNull()
job.cancel()
}
@Test
fun authenticate_DoesRun_ifNotUdfps() =
testScope.runTest {
fakeFingerprintManagerInteractor.sensorProps =
listOf(
FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
5 /* maxEnrollmentsPerUser */,
emptyList() /* ComponentInfoInternal */,
FingerprintSensorProperties.TYPE_POWER_BUTTON,
true /* resetLockoutRequiresHardwareAuthToken */
)
)
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal =
mutableListOf(FingerprintViewModel("a", 1, 3L))
val success = FingerprintAuthAttemptViewModel.Success(1)
fakeFingerprintManagerInteractor.authenticateAttempt = success
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
var authAttempt: FingerprintAuthAttemptViewModel? = null
val job = launch { underTest.authFlow.take(5).collectLatest { authAttempt = it } }
underTest.shouldAuthenticate(true)
navigationViewModel.onConfirmDevice(true, 10L)
advanceTimeBy(400)
runCurrent()
assertThat(authAttempt).isEqualTo(success)
job.cancel()
}
@Test
fun deleteDialog_showAndDismiss() = runTest {
val fingerprintToDelete = FingerprintViewModel("A", 1, 10L)
fakeFingerprintManagerInteractor.enrolledFingerprintsInternal = mutableListOf(fingerprintToDelete)
underTest =
FingerprintSettingsViewModel.FingerprintSettingsViewModelFactory(
defaultUserId,
fakeFingerprintManagerInteractor,
backgroundDispatcher,
navigationViewModel,
)
.create(FingerprintSettingsViewModel::class.java)
var dialog: PreferenceViewModel? = null
val dialogJob = launch { underTest.isShowingDialog.collect { dialog = it } }
// Move to the ShowSettings state
navigationViewModel.onConfirmDevice(true, 10L)
runCurrent()
underTest.onDeleteClicked(fingerprintToDelete)
runCurrent()
assertThat(dialog is PreferenceViewModel.DeleteDialog)
assertThat(dialog).isEqualTo(PreferenceViewModel.DeleteDialog(fingerprintToDelete))
underTest.deleteFingerprint(fingerprintToDelete)
underTest.onDeleteDialogFinished()
runCurrent()
assertThat(dialog).isNull()
dialogJob.cancel()
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 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.inputmethod;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.Looper;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
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;
@RunWith(AndroidJUnit4.class)
public class KeyboardSettingsFeatureProviderImplTest {
private Context mContext;
private KeyboardSettingsFeatureProviderImpl mFeatureProvider;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureProvider = new KeyboardSettingsFeatureProviderImpl();
}
@Test
public void supportsFirmwareUpdate_defaultValue_returnsFalse() {
assertThat(mFeatureProvider.supportsFirmwareUpdate()).isFalse();
}
@Test
public void addFirmwareUpdateCategory_defaultValue_returnsFalse() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
PreferenceManager preferenceManager = new PreferenceManager(mContext);
PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
assertThat(mFeatureProvider.addFirmwareUpdateCategory(mContext, screen)).isFalse();
}
@Test
public void getActionKeyIcon_defaultValue_returnsNull() {
assertThat(mFeatureProvider.getActionKeyIcon(mContext)).isNull();
}
}

View File

@@ -19,14 +19,12 @@ package com.android.settings.localepicker;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.verify;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.widget.FooterPreference;
import org.junit.Before;
@@ -39,7 +37,6 @@ import org.mockito.MockitoAnnotations;
public class LocaleHelperPreferenceControllerTest {
private Context mContext;
private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
private FakeFeatureFactory mFeatureFactory;
@Mock
private FooterPreference mMockFooterPreference;
@@ -52,16 +49,11 @@ public class LocaleHelperPreferenceControllerTest {
}
mContext = ApplicationProvider.getApplicationContext();
mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(mContext);
mFeatureFactory = FakeFeatureFactory.setupForTest();
}
@Test
public void updateFooterPreference_setFooterPreference_hasClickAction() {
mLocaleHelperPreferenceController.updateFooterPreference(mMockFooterPreference);
verify(mMockFooterPreference).setLearnMoreText(anyString());
mMockFooterPreference.setLearnMoreAction(v -> {
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext, SettingsEnums.ACTION_LANGUAGES_LEARN_MORE);
});
}
}

View File

@@ -16,26 +16,30 @@
package com.android.settings.network;
import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
import static com.android.settings.network.SubscriptionUtil.SUB_ID;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.android.settings.R;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -179,7 +183,7 @@ public class SubscriptionUtilTest {
@Ignore
@Test
public void getUniqueDisplayNames_identicalCarriers_fourDigitsUsed() {
// Both subscriptoins have the same display name.
// Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -209,7 +213,7 @@ public class SubscriptionUtilTest {
@Ignore
@Test
public void getUniqueDisplayNames_identicalCarriersAfterTrim_fourDigitsUsed() {
// Both subscriptoins have the same display name.
// Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -238,8 +242,8 @@ public class SubscriptionUtilTest {
@Ignore
@Test
public void getUniqueDisplayNames_phoneNumberBlocked_subscriptoinIdFallback() {
// Both subscriptoins have the same display name.
public void getUniqueDisplayNames_phoneNumberBlocked_subscriptionIdFallback() {
// Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
@@ -267,9 +271,9 @@ public class SubscriptionUtilTest {
@Ignore
@Test
public void getUniqueDisplayNames_phoneNumberIdentical_subscriptoinIdFallback() {
public void getUniqueDisplayNames_phoneNumberIdentical_subscriptionIdFallback() {
// TODO have three here from the same carrier
// Both subscriptoins have the same display name.
// Both subscriptions have the same display name.
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
@@ -444,6 +448,68 @@ public class SubscriptionUtilTest {
assertTrue(TextUtils.isEmpty(name));
}
@Test
public void getUniqueDisplayName_hasRecord_useRecordBeTheResult() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
when(info2.getSubscriptionId()).thenReturn(SUBID_2);
when(info1.getDisplayName()).thenReturn(CARRIER_1);
when(info2.getDisplayName()).thenReturn(CARRIER_1);
when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(
Arrays.asList(info1, info2));
SharedPreferences sp = mock(SharedPreferences.class);
when(mContext.getSharedPreferences(
KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
final CharSequence nameOfSub1 =
SubscriptionUtil.getUniqueSubscriptionDisplayName(info1, mContext);
final CharSequence nameOfSub2 =
SubscriptionUtil.getUniqueSubscriptionDisplayName(info2, mContext);
assertThat(nameOfSub1).isNotNull();
assertThat(nameOfSub2).isNotNull();
assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
assertEquals(CARRIER_1 + " 4321", nameOfSub2.toString());
}
@Test
public void getUniqueDisplayName_hasRecordAndNameIsChanged_doesNotUseRecordBeTheResult() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(SUBID_1);
when(info2.getSubscriptionId()).thenReturn(SUBID_2);
when(info1.getDisplayName()).thenReturn(CARRIER_1);
when(info2.getDisplayName()).thenReturn(CARRIER_2);
when(mSubMgr.getAvailableSubscriptionInfoList()).thenReturn(
Arrays.asList(info1, info2));
SharedPreferences sp = mock(SharedPreferences.class);
SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
when(mContext.getSharedPreferences(
KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME, Context.MODE_PRIVATE)).thenReturn(sp);
when(sp.edit()).thenReturn(editor);
when(editor.remove(anyString())).thenReturn(editor);
when(sp.getString(eq(SUB_ID + SUBID_1), anyString())).thenReturn(CARRIER_1 + " 6789");
when(sp.getString(eq(SUB_ID + SUBID_2), anyString())).thenReturn(CARRIER_1 + " 4321");
final CharSequence nameOfSub1 =
SubscriptionUtil.getUniqueSubscriptionDisplayName(info1, mContext);
final CharSequence nameOfSub2 =
SubscriptionUtil.getUniqueSubscriptionDisplayName(info2, mContext);
assertThat(nameOfSub1).isNotNull();
assertThat(nameOfSub2).isNotNull();
assertEquals(CARRIER_1 + " 6789", nameOfSub1.toString());
assertEquals(CARRIER_2.toString(), nameOfSub2.toString());
}
@Test
public void isInactiveInsertedPSim_nullSubInfo_doesNotCrash() {
assertThat(SubscriptionUtil.isInactiveInsertedPSim(null)).isFalse();
@@ -466,4 +532,60 @@ public class SubscriptionUtilTest {
assertTrue(SubscriptionUtil.isSimHardwareVisible(mContext));
}
@Test
public void isValidCachedDisplayName_matchesRule1_returnTrue() {
String originalName = "originalName";
String cacheString = "originalName 1234";
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
}
@Test
public void isValidCachedDisplayName_matchesRule2_returnTrue() {
String originalName = "original Name";
String cacheString = originalName + " " + 1234;
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isTrue();
}
@Test
public void isValidCachedDisplayName_nameIsEmpty1_returnFalse() {
String originalName = "original Name";
String cacheString = "";
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
@Test
public void isValidCachedDisplayName_nameIsEmpty2_returnFalse() {
String originalName = "";
String cacheString = "originalName 1234";
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
@Test
public void isValidCachedDisplayName_nameIsDifferent_returnFalse() {
String originalName = "original Name";
String cacheString = "originalName 1234";
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
@Test
public void isValidCachedDisplayName_noNumber_returnFalse() {
String originalName = "original Name";
String cacheString = originalName;
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
@Test
public void isValidCachedDisplayName_noSpace_returnFalse() {
String originalName = "original Name";
String cacheString = originalName;
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
}

View File

@@ -20,10 +20,13 @@ import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -49,6 +52,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
public class UiccSlotUtilTest {
@@ -738,6 +742,25 @@ public class UiccSlotUtilTest {
assertThat(testSlot).isFalse();
}
@Test
public void performSwitchToSlot_setSimSlotMapping() throws UiccSlotsException {
Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsBNoOrding();
UiccSlotUtil.performSwitchToSlot(mTelephonyManager, uiccSlotMappings, mContext);
verify(mTelephonyManager).setSimSlotMapping(any());
}
@Test
public void onReceiveSimSlotChangeReceiver_receiveAction_timerCountDown() {
CountDownLatch latch = spy(new CountDownLatch(1));
UiccSlotUtil.SimSlotChangeReceiver receive = new UiccSlotUtil.SimSlotChangeReceiver(latch);
receive.onReceive(mContext, new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED));
verify(latch).countDown();
}
private void compareTwoUiccSlotMappings(Collection<UiccSlotMapping> testUiccSlotMappings,
Collection<UiccSlotMapping> verifyUiccSlotMappings) {
assertThat(testUiccSlotMappings.size()).isEqualTo(verifyUiccSlotMappings.size());

View File

@@ -21,15 +21,20 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -63,7 +68,7 @@ public class MmsMessagePreferenceControllerTest {
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
mPreference = new SwitchPreference(mContext);
mPreference = spy(new SwitchPreference(mContext));
mController = new MmsMessagePreferenceController(mContext, "mms_message");
mController.init(SUB_ID);
mPreference.setKey(mController.getPreferenceKey());
@@ -118,4 +123,20 @@ public class MmsMessagePreferenceControllerTest {
verify(mTelephonyManager).setMobileDataPolicyEnabled(
TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false);
}
@Test
public void onStart_updatePreferenceUiState() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
PreferenceManager preferenceManager = new PreferenceManager(mContext);
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
preferenceScreen.addPreference(mPreference);
mController.displayPreference(preferenceScreen);
mController.onStart();
// First is preference initialization, and second is in onStart();
verify(mPreference, times(2)).setChecked(anyBoolean());
}
}

View File

@@ -25,7 +25,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityGsm;
@@ -37,6 +36,7 @@ import android.telephony.CellSignalStrengthGsm;
import android.telephony.CellSignalStrengthLte;
import android.telephony.TelephonyManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -310,4 +310,13 @@ public class NetworkSelectSettingsTest {
cellInfoGsm.setCellSignalStrength(cssg);
return cellInfoGsm;
}
@Test
@UiThreadTest
public void onPreferenceTreeClick_notNetworkOperatorPreference_noCrash() {
mNetworkSelectSettings.onCreateInitialization();
mNetworkSelectSettings.enablePreferenceScreen(true);
mNetworkSelectSettings.onPreferenceTreeClick(new Preference(mContext));
}
}

View File

@@ -0,0 +1,136 @@
/*
* 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.password;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SaveAndFinishWorkerTest {
@Test
public void testSetRequestWriteRepairModePassword_setLockCredentialFail() {
int userId = 0;
int flags = LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
var chosenCredential = LockscreenCredential.createPassword("1234");
var currentCredential = LockscreenCredential.createNone();
var worker = new SaveAndFinishWorker();
var lpu = mock(LockPatternUtils.class);
when(lpu.setLockCredential(chosenCredential, currentCredential, userId)).thenReturn(false);
worker.setRequestWriteRepairModePassword(true);
worker.prepare(lpu, chosenCredential, currentCredential, userId);
var result = worker.saveAndVerifyInBackground();
verify(lpu).setLockCredential(chosenCredential, currentCredential, userId);
verify(lpu, never()).verifyCredential(chosenCredential, userId, flags);
assertThat(result.first).isFalse();
}
@Test
public void testSetRequestWriteRepairModePassword_verifyCredentialFail() {
int userId = 0;
int flags = LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
var chosenCredential = LockscreenCredential.createPassword("1234");
var currentCredential = LockscreenCredential.createNone();
var worker = new SaveAndFinishWorker();
var lpu = mock(LockPatternUtils.class);
var response = VerifyCredentialResponse.fromError();
when(lpu.setLockCredential(chosenCredential, currentCredential, userId)).thenReturn(true);
when(lpu.verifyCredential(chosenCredential, userId, flags)).thenReturn(response);
worker.setRequestWriteRepairModePassword(true);
worker.prepare(lpu, chosenCredential, currentCredential, userId);
var result = worker.saveAndVerifyInBackground();
verify(lpu).setLockCredential(chosenCredential, currentCredential, userId);
verify(lpu).verifyCredential(chosenCredential, userId, flags);
assertThat(result.first).isTrue();
assertThat(result.second.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_WROTE_REPAIR_MODE_CREDENTIAL, true))
.isFalse();
}
@Test
public void testSetRequestWriteRepairModePassword_verifyCredentialSucceed() {
int userId = 0;
int flags = LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
var chosenCredential = LockscreenCredential.createPassword("1234");
var currentCredential = LockscreenCredential.createNone();
var worker = new SaveAndFinishWorker();
var lpu = mock(LockPatternUtils.class);
var response = new VerifyCredentialResponse.Builder().build();
when(lpu.setLockCredential(chosenCredential, currentCredential, userId)).thenReturn(true);
when(lpu.verifyCredential(chosenCredential, userId, flags)).thenReturn(response);
worker.setRequestWriteRepairModePassword(true);
worker.prepare(lpu, chosenCredential, currentCredential, userId);
var result = worker.saveAndVerifyInBackground();
verify(lpu).setLockCredential(chosenCredential, currentCredential, userId);
verify(lpu).verifyCredential(chosenCredential, userId, flags);
assertThat(result.first).isTrue();
assertThat(result.second.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_WROTE_REPAIR_MODE_CREDENTIAL, false))
.isTrue();
}
@Test
public void testSetRequestWriteRepairModePassword_verifyCredentialSucceed_noGkPwHandle() {
int userId = 0;
int flags = LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW
| LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
var chosenCredential = LockscreenCredential.createPassword("1234");
var currentCredential = LockscreenCredential.createNone();
var worker = new SaveAndFinishWorker();
var lpu = mock(LockPatternUtils.class);
var response = new VerifyCredentialResponse.Builder().build();
when(lpu.setLockCredential(chosenCredential, currentCredential, userId)).thenReturn(true);
when(lpu.verifyCredential(chosenCredential, userId, flags)).thenReturn(response);
worker.setRequestWriteRepairModePassword(true);
worker.setRequestGatekeeperPasswordHandle(true);
worker.prepare(lpu, chosenCredential, currentCredential, userId);
var result = worker.saveAndVerifyInBackground();
verify(lpu).setLockCredential(chosenCredential, currentCredential, userId);
verify(lpu).verifyCredential(chosenCredential, userId, flags);
assertThat(result.first).isTrue();
assertThat(result.second.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_WROTE_REPAIR_MODE_CREDENTIAL, false))
.isTrue();
assertThat(result.second.getLongExtra(
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, -1))
.isEqualTo(-1);
}
}

View File

@@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.LocaleList;
@@ -52,7 +51,6 @@ public class NumberingSystemItemControllerTest {
private NumberingPreferencesFragment mFragment;
private PreferenceScreen mPreferenceScreen;
private LocaleList mCacheLocale;
private FakeFeatureFactory mFeatureFactory;
@Before
@UiThreadTest
@@ -61,7 +59,6 @@ public class NumberingSystemItemControllerTest {
Looper.prepare();
}
mApplicationContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
mFragment = spy(new NumberingPreferencesFragment());
PreferenceManager preferenceManager = new PreferenceManager(mApplicationContext);
mPreferenceScreen = preferenceManager.createPreferenceScreen(mApplicationContext);
@@ -97,10 +94,6 @@ public class NumberingSystemItemControllerTest {
}
assertTrue(isCallingStartActivity);
verify(mFeatureFactory.metricsFeatureProvider).action(
mApplicationContext,
SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES,
"I_am_the_key");
}
@Test
@@ -121,9 +114,6 @@ public class NumberingSystemItemControllerTest {
mController.handlePreferenceTreeClick(preference);
verify(mFragment).setArguments(any());
verify(mFeatureFactory.metricsFeatureProvider).action(
mApplicationContext, SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES,
"test_key");
}
@Test

View File

@@ -27,6 +27,7 @@ import com.android.settings.aware.AwareFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.stylus.StylusFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider;
@@ -37,6 +38,7 @@ import com.android.settings.fuelgauge.BatteryStatusFeatureProvider;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.gestures.AssistGestureFeatureProvider;
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.inputmethod.KeyboardSettingsFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.overlay.DockUpdaterFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
@@ -90,6 +92,8 @@ public class FakeFeatureFactory extends FeatureFactory {
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
public WifiFeatureProvider mWifiFeatureProvider;
public KeyboardSettingsFeatureProvider mKeyboardSettingsFeatureProvider;
public StylusFeatureProvider mStylusFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -133,6 +137,8 @@ public class FakeFeatureFactory extends FeatureFactory {
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
mWifiFeatureProvider = mock(WifiFeatureProvider.class);
mKeyboardSettingsFeatureProvider = mock(KeyboardSettingsFeatureProvider.class);
mStylusFeatureProvider = mock(StylusFeatureProvider.class);
}
@Override
@@ -156,7 +162,7 @@ public class FakeFeatureFactory extends FeatureFactory {
}
@Override
public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider(Context context) {
public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider() {
return batterySettingsFeatureProvider;
}
@@ -289,4 +295,14 @@ public class FakeFeatureFactory extends FeatureFactory {
public WifiFeatureProvider getWifiFeatureProvider() {
return mWifiFeatureProvider;
}
@Override
public KeyboardSettingsFeatureProvider getKeyboardSettingsFeatureProvider() {
return mKeyboardSettingsFeatureProvider;
}
@Override
public StylusFeatureProvider getStylusFeatureProvider() {
return mStylusFeatureProvider;
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.wifi.details;
import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_CELLULAR;
import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_ETHERNET;
import static android.net.wifi.sharedconnectivity.app.HotspotNetwork.NETWORK_TYPE_WIFI;
import static android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Application;
import androidx.lifecycle.MutableLiveData;
import androidx.test.core.app.ApplicationProvider;
import com.android.wifitrackerlib.HotspotNetworkEntry;
import com.android.wifitrackerlib.WifiEntry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
public class WifiNetworkDetailsViewModelTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
Application mApplication = ApplicationProvider.getApplicationContext();
@Mock
MutableLiveData<WifiNetworkDetailsViewModel.HotspotNetworkData> mHotspotNetworkData;
@Mock
HotspotNetworkEntry mHotspotNetworkEntry;
WifiNetworkDetailsViewModel mViewModel;
ArgumentCaptor<WifiNetworkDetailsViewModel.HotspotNetworkData> mHotspotNetworkDataCaptor =
ArgumentCaptor.forClass(WifiNetworkDetailsViewModel.HotspotNetworkData.class);
@Before
public void setUp() {
mViewModel = new WifiNetworkDetailsViewModel(mApplication);
mViewModel.mHotspotNetworkData = mHotspotNetworkData;
}
@Test
public void setWifiEntry_notHotspotNetworkEntry_postValueNull() {
mViewModel.setWifiEntry(mock(WifiEntry.class));
verify(mHotspotNetworkData).postValue(null);
}
@Test
public void setWifiEntry_hotspotNetworkEntryWifi_postValueCorrect() {
when(mHotspotNetworkEntry.getNetworkType()).thenReturn(NETWORK_TYPE_WIFI);
when(mHotspotNetworkEntry.getUpstreamConnectionStrength()).thenReturn(WIFI_LEVEL_MAX);
when(mHotspotNetworkEntry.getBatteryPercentage()).thenReturn(100);
when(mHotspotNetworkEntry.isBatteryCharging()).thenReturn(false);
mViewModel.setWifiEntry(mHotspotNetworkEntry);
verify(mHotspotNetworkData).postValue(mHotspotNetworkDataCaptor.capture());
WifiNetworkDetailsViewModel.HotspotNetworkData data = mHotspotNetworkDataCaptor.getValue();
assertThat(data.getNetworkType()).isEqualTo(NETWORK_TYPE_WIFI);
assertThat(data.getUpstreamConnectionStrength()).isEqualTo(WIFI_LEVEL_MAX);
assertThat(data.getBatteryPercentage()).isEqualTo(100);
assertThat(data.isBatteryCharging()).isEqualTo(false);
}
@Test
public void setWifiEntry_hotspotNetworkEntryMobileData_postValueCorrect() {
when(mHotspotNetworkEntry.getNetworkType()).thenReturn(NETWORK_TYPE_CELLULAR);
when(mHotspotNetworkEntry.getUpstreamConnectionStrength())
.thenReturn(SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
when(mHotspotNetworkEntry.getBatteryPercentage()).thenReturn(0);
when(mHotspotNetworkEntry.isBatteryCharging()).thenReturn(true);
mViewModel.setWifiEntry(mHotspotNetworkEntry);
verify(mHotspotNetworkData).postValue(mHotspotNetworkDataCaptor.capture());
WifiNetworkDetailsViewModel.HotspotNetworkData data = mHotspotNetworkDataCaptor.getValue();
assertThat(data.getNetworkType()).isEqualTo(NETWORK_TYPE_CELLULAR);
assertThat(data.getUpstreamConnectionStrength()).isEqualTo(SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
assertThat(data.getBatteryPercentage()).isEqualTo(0);
assertThat(data.isBatteryCharging()).isEqualTo(true);
}
@Test
public void setWifiEntry_hotspotNetworkEntryEthernet_postValueCorrect() {
when(mHotspotNetworkEntry.getNetworkType()).thenReturn(NETWORK_TYPE_ETHERNET);
when(mHotspotNetworkEntry.getBatteryPercentage()).thenReturn(50);
when(mHotspotNetworkEntry.isBatteryCharging()).thenReturn(true);
mViewModel.setWifiEntry(mHotspotNetworkEntry);
verify(mHotspotNetworkData).postValue(mHotspotNetworkDataCaptor.capture());
WifiNetworkDetailsViewModel.HotspotNetworkData data = mHotspotNetworkDataCaptor.getValue();
assertThat(data.getNetworkType()).isEqualTo(NETWORK_TYPE_ETHERNET);
assertThat(data.getBatteryPercentage()).isEqualTo(50);
assertThat(data.isBatteryCharging()).isEqualTo(true);
}
@Test
public void getSecuritySummary_returnNotNull() {
assertThat(mViewModel.getHotspotNetworkData()).isNotNull();
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.wifi.dpp;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class WifiQrCodeTest {
@Test
public void testZxParsing_validCode() {
WifiNetworkConfig config = new WifiQrCode("WIFI:S:testAbC;T:nopass").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("testAbC");
assertThat(config.getSecurity()).isEqualTo("nopass");
config = new WifiQrCode(
"WIFI:S:reallyLONGone;T:WEP;P:somepasswo#%^**123rd").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("reallyLONGone");
assertThat(config.getSecurity()).isEqualTo("WEP");
assertThat(config.getPreSharedKey()).isEqualTo("somepasswo#%^**123rd");
config = new WifiQrCode("WIFI:S:anotherone;T:WPA;P:3#=3j9asicla").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("anotherone");
assertThat(config.getSecurity()).isEqualTo("WPA");
assertThat(config.getPreSharedKey()).isEqualTo("3#=3j9asicla");
config = new WifiQrCode("WIFI:S:xx;T:SAE;P:a").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("xx");
assertThat(config.getSecurity()).isEqualTo("SAE");
assertThat(config.getPreSharedKey()).isEqualTo("a");
}
@Test
public void testZxParsing_invalidCodeButShouldWork() {
WifiNetworkConfig config = new WifiQrCode(
"WIFI:S:testAbC; T:nopass").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("testAbC");
assertThat(config.getSecurity()).isEqualTo("nopass");
config = new WifiQrCode(
"WIFI:S:reallyLONGone;T:WEP; P:somepassword").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("reallyLONGone");
assertThat(config.getSecurity()).isEqualTo("WEP");
assertThat(config.getPreSharedKey()).isEqualTo("somepassword");
config = new WifiQrCode("WIFI: S:anotherone;T:WPA;P:abcdefghihklmn").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("anotherone");
assertThat(config.getSecurity()).isEqualTo("WPA");
assertThat(config.getPreSharedKey()).isEqualTo("abcdefghihklmn");
config = new WifiQrCode("WIFI: S:xx; T:SAE; P:a").getWifiNetworkConfig();
assertThat(config.getSsid()).isEqualTo("xx");
assertThat(config.getSecurity()).isEqualTo("SAE");
assertThat(config.getPreSharedKey()).isEqualTo("a");
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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.wifi.repository;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
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.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager;
import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
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;
public class SharedConnectivityRepositoryTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy
private Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private SharedConnectivityManager mManager;
private SharedConnectivityRepository mRepository;
private PendingIntent mIntent = PendingIntent
.getActivity(mContext, 0, new Intent("test"), FLAG_IMMUTABLE);
private SharedConnectivitySettingsState mState = new SharedConnectivitySettingsState.Builder()
.setInstantTetherSettingsPendingIntent(mIntent).build();
@Before
public void setUp() {
when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(mManager);
when(mManager.getSettingsState()).thenReturn(mState);
mRepository = spy(new SharedConnectivityRepository(mContext, true /* isConfigEnabled */));
}
@Test
public void constructor_configEnabled_registerCallback() {
verify(mManager).registerCallback(any(), any());
}
@Test
public void constructor_configNotEnabled_doNotRegisterCallback() {
SharedConnectivityManager manager = mock(SharedConnectivityManager.class);
when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(manager);
mRepository = new SharedConnectivityRepository(mContext, false /* isConfigEnabled */);
verify(manager, never()).registerCallback(any(), any());
}
@Test
public void isServiceAvailable_configEnabled_returnTrue() {
mRepository = new SharedConnectivityRepository(mContext, true /* isConfigEnabled */);
assertThat(mRepository.isServiceAvailable()).isTrue();
}
@Test
public void isServiceAvailable_configNotEnabled_returnFalse() {
mRepository = new SharedConnectivityRepository(mContext, false /* isConfigEnabled */);
assertThat(mRepository.isServiceAvailable()).isFalse();
}
@Test
public void getSettingsState_isNotNull() {
assertThat(mRepository.getSettingsState()).isNotNull();
}
@Test
public void handleLaunchSettings_managerNull_doNothing() {
when(mContext.getSystemService(SharedConnectivityManager.class)).thenReturn(null);
mRepository = spy(new SharedConnectivityRepository(mContext, true /* isConfigEnabled */));
mRepository.handleLaunchSettings();
verify(mRepository, never()).sendSettingsIntent(mIntent);
}
@Test
public void handleLaunchSettings_stageNull_doNothing() {
when(mManager.getSettingsState()).thenReturn(null);
mRepository.handleLaunchSettings();
verify(mRepository, never()).sendSettingsIntent(mIntent);
}
@Test
public void handleLaunchSettings_intentNull_doNothing() {
mState = new SharedConnectivitySettingsState.Builder()
.setInstantTetherSettingsPendingIntent(null).build();
when(mManager.getSettingsState()).thenReturn(mState);
mRepository.handleLaunchSettings();
verify(mRepository, never()).sendSettingsIntent(mIntent);
}
@Test
public void handleLaunchSettings_allReady_sendSettingsIntent() {
mRepository.handleLaunchSettings();
verify(mRepository).sendSettingsIntent(mIntent);
}
}

View File

@@ -20,6 +20,9 @@ import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2
import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ;
import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ;
import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ;
import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SPEED_5G_SUMMARY;
import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SPEED_6G_SUMMARY;
import static com.android.settings.wifi.tether.WifiHotspotSpeedViewModel.RES_SUMMARY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
@@ -128,7 +131,9 @@ public class WifiHotspotSpeedViewModelTest {
mViewModel.on6gAvailableChanged(true);
verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
assertThat(mViewModel.mSpeedInfoMap.get(SPEED_6GHZ).mIsEnabled).isTrue();
WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_6GHZ);
assertThat(speedInfo.mIsEnabled).isTrue();
assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SPEED_6G_SUMMARY));
}
@Test
@@ -139,7 +144,9 @@ public class WifiHotspotSpeedViewModelTest {
mViewModel.on6gAvailableChanged(false);
verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
assertThat(mViewModel.mSpeedInfoMap.get(SPEED_6GHZ).mIsEnabled).isFalse();
WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_6GHZ);
assertThat(speedInfo.mIsEnabled).isFalse();
assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SUMMARY_UNAVAILABLE));
}
@Test
@@ -150,7 +157,9 @@ public class WifiHotspotSpeedViewModelTest {
mViewModel.on5gAvailableChanged(true);
verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
assertThat(mViewModel.mSpeedInfoMap.get(SPEED_5GHZ).mIsEnabled).isTrue();
WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_5GHZ);
assertThat(speedInfo.mIsEnabled).isTrue();
assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SPEED_5G_SUMMARY));
}
@Test
@@ -161,7 +170,9 @@ public class WifiHotspotSpeedViewModelTest {
mViewModel.on5gAvailableChanged(false);
verify(mSpeedInfoMapData).setValue(mViewModel.mSpeedInfoMap);
assertThat(mViewModel.mSpeedInfoMap.get(SPEED_5GHZ).mIsEnabled).isFalse();
WifiHotspotSpeedViewModel.SpeedInfo speedInfo = mViewModel.mSpeedInfoMap.get(SPEED_5GHZ);
assertThat(speedInfo.mIsEnabled).isFalse();
assertThat(speedInfo.mSummary).isEqualTo(mContext.getString(RES_SUMMARY_UNAVAILABLE));
}
@Test

View File

@@ -16,6 +16,9 @@
package com.android.settings.wifi.tether;
import static com.android.settings.wifi.tether.WifiTetherViewModel.RES_INSTANT_HOTSPOT_SUMMARY_OFF;
import static com.android.settings.wifi.tether.WifiTetherViewModel.RES_INSTANT_HOTSPOT_SUMMARY_ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -23,12 +26,15 @@ import static org.mockito.Mockito.when;
import android.app.Application;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.sharedconnectivity.app.SharedConnectivitySettingsState;
import androidx.lifecycle.MutableLiveData;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.wifi.repository.SharedConnectivityRepository;
import com.android.settings.wifi.repository.WifiHotspotRepository;
import org.junit.Before;
@@ -36,6 +42,7 @@ 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;
@@ -45,8 +52,8 @@ import java.util.concurrent.Executor;
public class WifiTetherViewModelTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
Application mApplication;
@Spy
Application mApplication = ApplicationProvider.getApplicationContext();
@Mock
Executor mExecutor;
@Mock
@@ -57,6 +64,12 @@ public class WifiTetherViewModelTest {
MutableLiveData<Integer> mSpeedType;
@Mock
private MutableLiveData<Boolean> mRestarting;
@Mock
private SharedConnectivityRepository mSharedConnectivityRepository;
@Mock
private MutableLiveData<SharedConnectivitySettingsState> mSettingsState;
@Mock
private MutableLiveData<String> mInstantHotspotSummary;
WifiTetherViewModel mViewModel;
@@ -70,8 +83,18 @@ public class WifiTetherViewModelTest {
when(mWifiHotspotRepository.getSecurityType()).thenReturn(mSecurityType);
when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType);
when(mWifiHotspotRepository.getRestarting()).thenReturn(mRestarting);
when(featureFactory.getWifiFeatureProvider().getSharedConnectivityRepository())
.thenReturn(mSharedConnectivityRepository);
when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(true);
when(mSharedConnectivityRepository.getSettingsState()).thenReturn(mSettingsState);
mViewModel = new WifiTetherViewModel(mApplication);
mViewModel.mInstantHotspotSummary = mInstantHotspotSummary;
}
@Test
public void constructor_observeData() {
verify(mSettingsState).observeForever(mViewModel.mInstantHotspotStateObserver);
}
@Test
@@ -83,6 +106,7 @@ public class WifiTetherViewModelTest {
verify(mSecurityType).removeObserver(mViewModel.mSecurityTypeObserver);
verify(mSpeedType).removeObserver(mViewModel.mSpeedTypeObserver);
verify(mSettingsState).removeObserver(mViewModel.mInstantHotspotStateObserver);
}
@Test
@@ -141,4 +165,59 @@ public class WifiTetherViewModelTest {
public void getRestarting_shouldNotReturnNull() {
assertThat(mViewModel.getRestarting()).isNotNull();
}
@Test
public void isInstantHotspotFeatureAvailable_serviceAvailable_returnTrue() {
when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(true);
assertThat(mViewModel.isInstantHotspotFeatureAvailable()).isTrue();
}
@Test
public void isInstantHotspotFeatureAvailable_serviceNotAvailable_returnFalse() {
when(mSharedConnectivityRepository.isServiceAvailable()).thenReturn(false);
assertThat(mViewModel.isInstantHotspotFeatureAvailable()).isFalse();
}
@Test
public void getInstantHotspotSummary_isNotNull() {
assertThat(mViewModel.getInstantHotspotSummary()).isNotNull();
}
@Test
public void onInstantHotspotStateChanged_stageNull_summarySetValueNull() {
mViewModel.onInstantHotspotStateChanged(null);
verify(mInstantHotspotSummary).setValue(null);
}
@Test
public void onInstantHotspotStateChanged_stateEnabled_summarySetValueOn() {
SharedConnectivitySettingsState state = new SharedConnectivitySettingsState.Builder()
.setInstantTetherEnabled(true).build();
mViewModel.onInstantHotspotStateChanged(state);
verify(mInstantHotspotSummary)
.setValue(mApplication.getString(RES_INSTANT_HOTSPOT_SUMMARY_ON));
}
@Test
public void onInstantHotspotStateChanged_stateNotEnabled_recordVisibleSummaryOff() {
SharedConnectivitySettingsState state = new SharedConnectivitySettingsState.Builder()
.setInstantTetherEnabled(false).build();
mViewModel.onInstantHotspotStateChanged(state);
verify(mInstantHotspotSummary)
.setValue(mApplication.getString(RES_INSTANT_HOTSPOT_SUMMARY_OFF));
}
@Test
public void launchInstantHotspotSettings_launchSettingsByRepository() {
mViewModel.launchInstantHotspotSettings();
verify(mSharedConnectivityRepository).launchSettings();
}
}