From 5a574a1db4bacd9bffcfb8f8be30082fa9627a92 Mon Sep 17 00:00:00 2001 From: Alejandro Nijamkin Date: Mon, 7 Nov 2022 12:17:52 -0800 Subject: [PATCH] Legacy setting syncer. We need to respect the user's settings when we update quick affordance selections and vice versa. See the documentation of the class for more details. Fix: 256662760 Test: added unit tests. Manually verified that updating settings and selections updates the other side as expected. Change-Id: Icd8ff1558fe887ca765ce325b97e7815f124b0db --- ...guardQuickAffordanceLegacySettingSyncer.kt | 214 ++++++++++++++++++ .../KeyguardQuickAffordanceRepository.kt | 6 + .../KeyguardQuickAffordanceProviderTest.kt | 45 ++-- ...dQuickAffordanceLegacySettingSyncerTest.kt | 191 ++++++++++++++++ .../KeyguardQuickAffordanceRepositoryTest.kt | 44 ++-- ...ckAffordanceInteractorParameterizedTest.kt | 43 ++-- .../KeyguardQuickAffordanceInteractorTest.kt | 43 ++-- .../KeyguardBottomAreaViewModelTest.kt | 43 ++-- 8 files changed, 548 insertions(+), 81 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt new file mode 100644 index 0000000000000..766096f1fa2bc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt @@ -0,0 +1,214 @@ +/* + * 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.systemui.keyguard.data.quickaffordance + +import android.os.UserHandle +import android.provider.Settings +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer.Companion.BINDINGS +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots +import com.android.systemui.util.settings.SecureSettings +import com.android.systemui.util.settings.SettingsProxyExt.observerFlow +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * Keeps quick affordance selections and legacy user settings in sync. + * + * "Legacy user settings" are user settings like: Settings > Display > Lock screen > "Show device + * controls" Settings > Display > Lock screen > "Show wallet" + * + * Quick affordance selections are the ones available through the new custom lock screen experience + * from Settings > Wallpaper & Style. + * + * This class keeps these in sync, mostly for backwards compatibility purposes and in order to not + * "forget" an existing legacy user setting when the device gets updated with a version of System UI + * that has the new customizable lock screen feature. + * + * The way it works is that, when [startSyncing] is called, the syncer starts coroutines to listen + * for changes in both legacy user settings and their respective affordance selections. Whenever one + * of each pair is changed, the other member of that pair is also updated to match. For example, if + * the user turns on "Show device controls", we automatically select the home controls affordance + * for the preferred slot. Conversely, when the home controls affordance is unselected by the user, + * we set the "Show device controls" setting to "off". + * + * The class can be configured by updating its list of triplets in the code under [BINDINGS]. + */ +@SysUISingleton +class KeyguardQuickAffordanceLegacySettingSyncer +@Inject +constructor( + @Application private val scope: CoroutineScope, + @Background private val backgroundDispatcher: CoroutineDispatcher, + private val secureSettings: SecureSettings, + private val selectionsManager: KeyguardQuickAffordanceSelectionManager, +) { + companion object { + private val BINDINGS = + listOf( + Binding( + settingsKey = Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, + slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, + affordanceId = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS, + ), + Binding( + settingsKey = Settings.Secure.LOCKSCREEN_SHOW_WALLET, + slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, + affordanceId = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET, + ), + Binding( + settingsKey = Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, + slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, + affordanceId = BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER, + ), + ) + } + + fun startSyncing( + bindings: List = BINDINGS, + ): Job { + return scope.launch { bindings.forEach { binding -> startSyncing(this, binding) } } + } + + private fun startSyncing( + scope: CoroutineScope, + binding: Binding, + ) { + secureSettings + .observerFlow( + names = arrayOf(binding.settingsKey), + userId = UserHandle.USER_ALL, + ) + .map { + isSet( + settingsKey = binding.settingsKey, + ) + } + .distinctUntilChanged() + .onEach { isSet -> + if (isSelected(binding.affordanceId) != isSet) { + if (isSet) { + select( + slotId = binding.slotId, + affordanceId = binding.affordanceId, + ) + } else { + unselect( + affordanceId = binding.affordanceId, + ) + } + } + } + .flowOn(backgroundDispatcher) + .launchIn(scope) + + selectionsManager.selections + .map { it.values.flatten().toSet() } + .map { it.contains(binding.affordanceId) } + .distinctUntilChanged() + .onEach { isSelected -> + if (isSet(binding.settingsKey) != isSelected) { + set(binding.settingsKey, isSelected) + } + } + .flowOn(backgroundDispatcher) + .launchIn(scope) + } + + private fun isSelected( + affordanceId: String, + ): Boolean { + return selectionsManager + .getSelections() // Map> + .values // Collection> + .flatten() // List + .toSet() // Set + .contains(affordanceId) + } + + private fun select( + slotId: String, + affordanceId: String, + ) { + val affordanceIdsAtSlotId = selectionsManager.getSelections()[slotId] ?: emptyList() + selectionsManager.setSelections( + slotId = slotId, + affordanceIds = affordanceIdsAtSlotId + listOf(affordanceId), + ) + } + + private fun unselect( + affordanceId: String, + ) { + val currentSelections = selectionsManager.getSelections() + val slotIdsContainingAffordanceId = + currentSelections + .filter { (_, affordanceIds) -> affordanceIds.contains(affordanceId) } + .map { (slotId, _) -> slotId } + + slotIdsContainingAffordanceId.forEach { slotId -> + val currentAffordanceIds = currentSelections[slotId] ?: emptyList() + val affordanceIdsAfterUnselecting = + currentAffordanceIds.toMutableList().apply { remove(affordanceId) } + + selectionsManager.setSelections( + slotId = slotId, + affordanceIds = affordanceIdsAfterUnselecting, + ) + } + } + + private fun isSet( + settingsKey: String, + ): Boolean { + return secureSettings.getIntForUser( + settingsKey, + 0, + UserHandle.USER_CURRENT, + ) != 0 + } + + private suspend fun set( + settingsKey: String, + isSet: Boolean, + ) { + withContext(backgroundDispatcher) { + secureSettings.putInt( + settingsKey, + if (isSet) 1 else 0, + ) + } + } + + data class Binding( + val settingsKey: String, + val slotId: String, + val affordanceId: String, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt index a1fdbe4a90126..533b3abf4fb65 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt @@ -22,6 +22,7 @@ import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation @@ -40,6 +41,7 @@ constructor( @Application private val appContext: Context, @Application private val scope: CoroutineScope, private val selectionManager: KeyguardQuickAffordanceSelectionManager, + legacySettingSyncer: KeyguardQuickAffordanceLegacySettingSyncer, private val configs: Set<@JvmSuppressWildcards KeyguardQuickAffordanceConfig>, ) { /** @@ -83,6 +85,10 @@ constructor( } } + init { + legacySettingSyncer.startSyncing() + } + /** * Returns a snapshot of the [KeyguardQuickAffordanceConfig] instances of the affordances at the * slot with the given ID. The configs are sorted in descending priority order. diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt index 5228e1774edf6..8395f02cbc41e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository @@ -41,6 +42,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -71,26 +73,28 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) underTest = KeyguardQuickAffordanceProvider() + val scope = CoroutineScope(IMMEDIATE) + val selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ) val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = CoroutineScope(IMMEDIATE), - selectionManager = - KeyguardQuickAffordanceSelectionManager( - context = context, - userFileManager = - mock().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) - .thenReturn(FakeSharedPreferences()) - }, - userTracker = userTracker, - ), + scope = scope, + selectionManager = selectionManager, configs = setOf( FakeKeyguardQuickAffordanceConfig( @@ -102,6 +106,13 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { pickerIconResourceId = 2, ), ), + legacySettingSyncer = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = scope, + backgroundDispatcher = IMMEDIATE, + secureSettings = FakeSettings(), + selectionsManager = selectionManager, + ), ) underTest.interactor = KeyguardQuickAffordanceInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt new file mode 100644 index 0000000000000..8ef921eaa50ac --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt @@ -0,0 +1,191 @@ +/* + * 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.systemui.keyguard.data.quickaffordance + +import android.content.Context +import android.content.res.Resources +import android.provider.Settings +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots +import com.android.systemui.util.FakeSharedPreferences +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() { + + @Mock private lateinit var sharedPrefs: FakeSharedPreferences + + private lateinit var underTest: KeyguardQuickAffordanceLegacySettingSyncer + + private lateinit var testScope: TestScope + private lateinit var testDispatcher: TestDispatcher + private lateinit var selectionManager: KeyguardQuickAffordanceSelectionManager + private lateinit var settings: FakeSettings + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + val context: Context = mock() + sharedPrefs = FakeSharedPreferences() + whenever(context.getSharedPreferences(anyString(), any())).thenReturn(sharedPrefs) + val resources: Resources = mock() + whenever(resources.getStringArray(R.array.config_keyguardQuickAffordanceDefaults)) + .thenReturn(emptyArray()) + whenever(context.resources).thenReturn(resources) + + testDispatcher = UnconfinedTestDispatcher() + testScope = TestScope(testDispatcher) + selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = FakeUserTracker(), + ) + settings = FakeSettings() + settings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 0) + settings.putInt(Settings.Secure.LOCKSCREEN_SHOW_WALLET, 0) + settings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_QR_CODE_SCANNER, 0) + + underTest = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = testScope, + backgroundDispatcher = testDispatcher, + secureSettings = settings, + selectionsManager = selectionManager, + ) + } + + @Test + fun `Setting a setting selects the affordance`() = + testScope.runTest { + val job = underTest.startSyncing() + + settings.putInt( + Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, + 1, + ) + + assertThat( + selectionManager + .getSelections() + .getOrDefault( + KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, + emptyList() + ) + ) + .contains(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS) + + job.cancel() + } + + @Test + fun `Clearing a setting selects the affordance`() = + testScope.runTest { + val job = underTest.startSyncing() + + settings.putInt( + Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, + 1, + ) + settings.putInt( + Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, + 0, + ) + + assertThat( + selectionManager + .getSelections() + .getOrDefault( + KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, + emptyList() + ) + ) + .doesNotContain(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS) + + job.cancel() + } + + @Test + fun `Selecting an affordance sets its setting`() = + testScope.runTest { + val job = underTest.startSyncing() + + selectionManager.setSelections( + KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, + listOf(BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET) + ) + + advanceUntilIdle() + assertThat(settings.getInt(Settings.Secure.LOCKSCREEN_SHOW_WALLET)).isEqualTo(1) + + job.cancel() + } + + @Test + fun `Unselecting an affordance clears its setting`() = + testScope.runTest { + val job = underTest.startSyncing() + + selectionManager.setSelections( + KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, + listOf(BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET) + ) + selectionManager.setSelections( + KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, + emptyList() + ) + + assertThat(settings.getInt(Settings.Secure.LOCKSCREEN_SHOW_WALLET)).isEqualTo(0) + + job.cancel() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index e56e1b93dcfb6..d8a360567a07f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -22,6 +22,7 @@ import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation @@ -30,6 +31,7 @@ import com.android.systemui.settings.UserFileManager import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -58,25 +60,35 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { fun setUp() { config1 = FakeKeyguardQuickAffordanceConfig("built_in:1") config2 = FakeKeyguardQuickAffordanceConfig("built_in:2") + val scope = CoroutineScope(IMMEDIATE) + val selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = FakeUserTracker(), + ) + underTest = KeyguardQuickAffordanceRepository( appContext = context, - scope = CoroutineScope(IMMEDIATE), - selectionManager = - KeyguardQuickAffordanceSelectionManager( - context = context, - userFileManager = - mock().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) - .thenReturn(FakeSharedPreferences()) - }, - userTracker = FakeUserTracker(), + scope = scope, + selectionManager = selectionManager, + legacySettingSyncer = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = scope, + backgroundDispatcher = IMMEDIATE, + secureSettings = FakeSettings(), + selectionsManager = selectionManager, ), configs = setOf(config1, config2), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index 3b1cbb1bd6203..1e1d3f19d83cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository @@ -44,6 +45,7 @@ import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.runBlockingTest @@ -234,25 +236,34 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { ) val qrCodeScanner = FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER) + val scope = CoroutineScope(IMMEDIATE) + val selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ) val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = CoroutineScope(IMMEDIATE), - selectionManager = - KeyguardQuickAffordanceSelectionManager( - context = context, - userFileManager = - mock().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) - .thenReturn(FakeSharedPreferences()) - }, - userTracker = userTracker, + scope = scope, + selectionManager = selectionManager, + legacySettingSyncer = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = scope, + backgroundDispatcher = IMMEDIATE, + secureSettings = FakeSettings(), + selectionsManager = selectionManager, ), configs = setOf(homeControls, quickAccessWallet, qrCodeScanner), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 1374c43ebe1ba..c47e6f52c5962 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository @@ -42,6 +43,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -93,26 +95,35 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) qrCodeScanner = FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER) + val scope = CoroutineScope(IMMEDIATE) + val selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ) val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = CoroutineScope(IMMEDIATE), - selectionManager = - KeyguardQuickAffordanceSelectionManager( - context = context, - userFileManager = - mock().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) - .thenReturn(FakeSharedPreferences()) - }, - userTracker = userTracker, + scope = scope, + selectionManager = selectionManager, + legacySettingSyncer = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = scope, + backgroundDispatcher = IMMEDIATE, + secureSettings = FakeSettings(), + selectionsManager = selectionManager, ), configs = setOf(homeControls, quickAccessWallet, qrCodeScanner), ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index abe8a304a4ef7..ecc63ecc879d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig +import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository @@ -44,6 +45,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlin.math.max import kotlin.math.min @@ -118,25 +120,34 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { whenever(userTracker.userHandle).thenReturn(mock()) whenever(lockPatternUtils.getStrongAuthForUser(anyInt())) .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED) + val scope = CoroutineScope(IMMEDIATE) + val selectionManager = + KeyguardQuickAffordanceSelectionManager( + context = context, + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ) val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = CoroutineScope(IMMEDIATE), - selectionManager = - KeyguardQuickAffordanceSelectionManager( - context = context, - userFileManager = - mock().apply { - whenever( - getSharedPreferences( - anyString(), - anyInt(), - anyInt(), - ) - ) - .thenReturn(FakeSharedPreferences()) - }, - userTracker = userTracker, + scope = scope, + selectionManager = selectionManager, + legacySettingSyncer = + KeyguardQuickAffordanceLegacySettingSyncer( + scope = scope, + backgroundDispatcher = IMMEDIATE, + secureSettings = FakeSettings(), + selectionsManager = selectionManager, ), configs = setOf(