diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt index 0f4581ce3e616..82209637e9fa7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt @@ -31,7 +31,6 @@ import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCall import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract import javax.inject.Inject -import kotlinx.coroutines.runBlocking class KeyguardQuickAffordanceProvider : ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer { @@ -171,12 +170,11 @@ class KeyguardQuickAffordanceProvider : throw IllegalArgumentException("Cannot insert selection, affordance ID was empty!") } - val success = runBlocking { + val success = interactor.select( slotId = slotId, affordanceId = affordanceId, ) - } return if (success) { Log.d(TAG, "Successfully selected $affordanceId for slot $slotId") @@ -196,7 +194,7 @@ class KeyguardQuickAffordanceProvider : ) ) .apply { - val affordanceIdsBySlotId = runBlocking { interactor.getSelections() } + val affordanceIdsBySlotId = interactor.getSelections() affordanceIdsBySlotId.entries.forEach { (slotId, affordanceIds) -> affordanceIds.forEach { affordanceId -> addRow( @@ -271,12 +269,11 @@ class KeyguardQuickAffordanceProvider : ) } - val deleted = runBlocking { + val deleted = interactor.unselect( slotId = slotId, affordanceId = affordanceId, ) - } return if (deleted) { Log.d(TAG, "Successfully unselected $affordanceId for slot $slotId") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt index 9c9354fec6950..d89ac37322b42 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt @@ -17,46 +17,105 @@ package com.android.systemui.keyguard.data.quickaffordance +import android.content.Context +import android.content.SharedPreferences +import androidx.annotation.VisibleForTesting +import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.settings.UserFileManager +import com.android.systemui.settings.UserTracker import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.flatMapLatest /** * Manages and provides access to the current "selections" of keyguard quick affordances, answering * the question "which affordances should the keyguard show?". */ @SysUISingleton -class KeyguardQuickAffordanceSelectionManager @Inject constructor() { +class KeyguardQuickAffordanceSelectionManager +@Inject +constructor( + private val userFileManager: UserFileManager, + private val userTracker: UserTracker, +) { - // TODO(b/254858695): implement a persistence layer (database). - private val _selections = MutableStateFlow>>(emptyMap()) + private val sharedPrefs: SharedPreferences + get() = + userFileManager.getSharedPreferences( + FILE_NAME, + Context.MODE_PRIVATE, + userTracker.userId, + ) + + private val userId: Flow = conflatedCallbackFlow { + val callback = + object : UserTracker.Callback { + override fun onUserChanged(newUser: Int, userContext: Context) { + trySendWithFailureLogging(newUser, TAG) + } + } + + userTracker.addCallback(callback) { it.run() } + trySendWithFailureLogging(userTracker.userId, TAG) + + awaitClose { userTracker.removeCallback(callback) } + } /** IDs of affordances to show, indexed by slot ID, and sorted in descending priority order. */ - val selections: Flow>> = _selections.asStateFlow() + val selections: Flow>> = + userId.flatMapLatest { + conflatedCallbackFlow { + val listener = + SharedPreferences.OnSharedPreferenceChangeListener { _, _ -> + trySend(getSelections()) + } + + sharedPrefs.registerOnSharedPreferenceChangeListener(listener) + send(getSelections()) + + awaitClose { sharedPrefs.unregisterOnSharedPreferenceChangeListener(listener) } + } + } /** * Returns a snapshot of the IDs of affordances to show, indexed by slot ID, and sorted in * descending priority order. */ - suspend fun getSelections(): Map> { - return _selections.value + fun getSelections(): Map> { + val slotKeys = sharedPrefs.all.keys.filter { it.startsWith(KEY_PREFIX_SLOT) } + return slotKeys.associate { key -> + val slotId = key.substring(KEY_PREFIX_SLOT.length) + val value = sharedPrefs.getString(key, null) + val affordanceIds = + if (!value.isNullOrEmpty()) { + value.split(DELIMITER) + } else { + emptyList() + } + slotId to affordanceIds + } } /** * Updates the IDs of affordances to show at the slot with the given ID. The order of affordance * IDs should be descending priority order. */ - suspend fun setSelections( + fun setSelections( slotId: String, affordanceIds: List, ) { - // Must make a copy of the map and update it, otherwise, the MutableStateFlow won't emit - // when we set its value to the same instance of the original map, even if we change the - // map by updating the value of one of its keys. - val copy = _selections.value.toMutableMap() - copy[slotId] = affordanceIds - _selections.value = copy + val key = "$KEY_PREFIX_SLOT$slotId" + val value = affordanceIds.joinToString(DELIMITER) + sharedPrefs.edit().putString(key, value).apply() + } + + companion object { + private const val TAG = "KeyguardQuickAffordanceSelectionManager" + @VisibleForTesting const val FILE_NAME = "quick_affordance_selections" + private const val KEY_PREFIX_SLOT = "slot_" + private const val DELIMITER = "," } } 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 9fda98c5f7c2c..a1fdbe4a90126 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 @@ -21,19 +21,16 @@ import android.content.Context import com.android.systemui.R 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.KeyguardQuickAffordanceConfig import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch /** Abstracts access to application state related to keyguard quick affordances. */ @SysUISingleton @@ -42,7 +39,6 @@ class KeyguardQuickAffordanceRepository constructor( @Application private val appContext: Context, @Application private val scope: CoroutineScope, - @Background private val backgroundDispatcher: CoroutineDispatcher, private val selectionManager: KeyguardQuickAffordanceSelectionManager, private val configs: Set<@JvmSuppressWildcards KeyguardQuickAffordanceConfig>, ) { @@ -91,7 +87,7 @@ constructor( * 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. */ - suspend fun getSelections(slotId: String): List { + fun getSelections(slotId: String): List { val selections = selectionManager.getSelections().getOrDefault(slotId, emptyList()) return configs.filter { selections.contains(it.key) } } @@ -100,7 +96,7 @@ constructor( * Returns a snapshot of the IDs of the selected affordances, indexed by slot ID. The configs * are sorted in descending priority order. */ - suspend fun getSelections(): Map> { + fun getSelections(): Map> { return selectionManager.getSelections() } @@ -112,12 +108,10 @@ constructor( slotId: String, affordanceIds: List, ) { - scope.launch(backgroundDispatcher) { - selectionManager.setSelections( - slotId = slotId, - affordanceIds = affordanceIds, - ) - } + selectionManager.setSelections( + slotId = slotId, + affordanceIds = affordanceIds, + ) } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index 92caa89bb0e8b..88fed18574cd6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -117,7 +117,7 @@ constructor( * * @return `true` if the affordance was selected successfully; `false` otherwise. */ - suspend fun select(slotId: String, affordanceId: String): Boolean { + fun select(slotId: String, affordanceId: String): Boolean { check(isUsingRepository) val slots = repository.get().getSlotPickerRepresentations() @@ -152,7 +152,7 @@ constructor( * @return `true` if the affordance was successfully removed; `false` otherwise (for example, if * the affordance was not on the slot to begin with). */ - suspend fun unselect(slotId: String, affordanceId: String?): Boolean { + fun unselect(slotId: String, affordanceId: String?): Boolean { check(isUsingRepository) val slots = repository.get().getSlotPickerRepresentations() @@ -187,7 +187,7 @@ constructor( } /** Returns affordance IDs indexed by slot ID, for all known slots. */ - suspend fun getSelections(): Map> { + fun getSelections(): Map> { check(isUsingRepository) val selections = repository.get().getSelections() 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 ed08849fe70c0..2d0f9e264f692 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt @@ -33,11 +33,14 @@ import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepo import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots 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.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -46,6 +49,8 @@ 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.Mockito.verify import org.mockito.MockitoAnnotations @@ -70,8 +75,21 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { KeyguardQuickAffordanceRepository( appContext = context, scope = CoroutineScope(IMMEDIATE), - backgroundDispatcher = IMMEDIATE, - selectionManager = KeyguardQuickAffordanceSelectionManager(), + selectionManager = + KeyguardQuickAffordanceSelectionManager( + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ), configs = setOf( FakeKeyguardQuickAffordanceConfig( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt index d2422ad7b53b3..b8bef1a9d6f36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt @@ -17,111 +17,215 @@ package com.android.systemui.keyguard.data.quickaffordance +import android.content.SharedPreferences +import android.content.pm.UserInfo +import androidx.test.core.app.ActivityScenario.launch import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.UserFileManager +import com.android.systemui.util.FakeSharedPreferences +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.UnconfinedTestDispatcher +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 @SmallTest @RunWith(JUnit4::class) class KeyguardQuickAffordanceSelectionManagerTest : SysuiTestCase() { + @Mock private lateinit var userFileManager: UserFileManager + private lateinit var underTest: KeyguardQuickAffordanceSelectionManager + private lateinit var userTracker: FakeUserTracker + private lateinit var sharedPrefs: MutableMap + @Before fun setUp() { - underTest = KeyguardQuickAffordanceSelectionManager() + MockitoAnnotations.initMocks(this) + sharedPrefs = mutableMapOf() + whenever(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())).thenAnswer { + val userId = it.arguments[2] as Int + sharedPrefs.getOrPut(userId) { FakeSharedPreferences() } + } + userTracker = FakeUserTracker() + + underTest = + KeyguardQuickAffordanceSelectionManager( + userFileManager = userFileManager, + userTracker = userTracker, + ) } @Test - fun setSelections() = - runBlocking(IMMEDIATE) { - var affordanceIdsBySlotId: Map>? = null - val job = underTest.selections.onEach { affordanceIdsBySlotId = it }.launchIn(this) - val slotId1 = "slot1" - val slotId2 = "slot2" - val affordanceId1 = "affordance1" - val affordanceId2 = "affordance2" - val affordanceId3 = "affordance3" + fun setSelections() = runTest { + val affordanceIdsBySlotId = mutableListOf>>() + val job = + launch(UnconfinedTestDispatcher()) { + underTest.selections.toList(affordanceIdsBySlotId) + } + val slotId1 = "slot1" + val slotId2 = "slot2" + val affordanceId1 = "affordance1" + val affordanceId2 = "affordance2" + val affordanceId3 = "affordance3" - underTest.setSelections( - slotId = slotId1, - affordanceIds = listOf(affordanceId1), + underTest.setSelections( + slotId = slotId1, + affordanceIds = listOf(affordanceId1), + ) + assertSelections( + affordanceIdsBySlotId.last(), + mapOf( + slotId1 to listOf(affordanceId1), + ), + ) + + underTest.setSelections( + slotId = slotId2, + affordanceIds = listOf(affordanceId2), + ) + assertSelections( + affordanceIdsBySlotId.last(), + mapOf( + slotId1 to listOf(affordanceId1), + slotId2 to listOf(affordanceId2), ) - assertSelections( - affordanceIdsBySlotId, + ) + + underTest.setSelections( + slotId = slotId1, + affordanceIds = listOf(affordanceId1, affordanceId3), + ) + assertSelections( + affordanceIdsBySlotId.last(), + mapOf( + slotId1 to listOf(affordanceId1, affordanceId3), + slotId2 to listOf(affordanceId2), + ) + ) + + underTest.setSelections( + slotId = slotId1, + affordanceIds = listOf(affordanceId3), + ) + assertSelections( + affordanceIdsBySlotId.last(), + mapOf( + slotId1 to listOf(affordanceId3), + slotId2 to listOf(affordanceId2), + ) + ) + + underTest.setSelections( + slotId = slotId2, + affordanceIds = listOf(), + ) + assertSelections( + affordanceIdsBySlotId.last(), + mapOf( + slotId1 to listOf(affordanceId3), + slotId2 to listOf(), + ) + ) + + job.cancel() + } + + @Test + fun `remembers selections by user`() = runTest { + val slot1 = "slot_1" + val slot2 = "slot_2" + val affordance1 = "affordance_1" + val affordance2 = "affordance_2" + val affordance3 = "affordance_3" + + val affordanceIdsBySlotId = mutableListOf>>() + val job = + launch(UnconfinedTestDispatcher()) { + underTest.selections.toList(affordanceIdsBySlotId) + } + + val userInfos = + listOf( + UserInfo(/* id= */ 0, "zero", /* flags= */ 0), + UserInfo(/* id= */ 1, "one", /* flags= */ 0), + ) + userTracker.set( + userInfos = userInfos, + selectedUserIndex = 0, + ) + underTest.setSelections( + slotId = slot1, + affordanceIds = listOf(affordance1), + ) + underTest.setSelections( + slotId = slot2, + affordanceIds = listOf(affordance2), + ) + + // Switch to user 1 + userTracker.set( + userInfos = userInfos, + selectedUserIndex = 1, + ) + // We never set selections on user 1, so it should be empty. + assertSelections( + observed = affordanceIdsBySlotId.last(), + expected = emptyMap(), + ) + // Now, let's set selections on user 1. + underTest.setSelections( + slotId = slot1, + affordanceIds = listOf(affordance2), + ) + underTest.setSelections( + slotId = slot2, + affordanceIds = listOf(affordance3), + ) + assertSelections( + observed = affordanceIdsBySlotId.last(), + expected = mapOf( - slotId1 to listOf(affordanceId1), + slot1 to listOf(affordance2), + slot2 to listOf(affordance3), ), - ) + ) - underTest.setSelections( - slotId = slotId2, - affordanceIds = listOf(affordanceId2), - ) - assertSelections( - affordanceIdsBySlotId, + // Switch back to user 0. + userTracker.set( + userInfos = userInfos, + selectedUserIndex = 0, + ) + // Assert that we still remember the old selections for user 0. + assertSelections( + observed = affordanceIdsBySlotId.last(), + expected = mapOf( - slotId1 to listOf(affordanceId1), - slotId2 to listOf(affordanceId2), - ) - ) + slot1 to listOf(affordance1), + slot2 to listOf(affordance2), + ), + ) - underTest.setSelections( - slotId = slotId1, - affordanceIds = listOf(affordanceId1, affordanceId3), - ) - assertSelections( - affordanceIdsBySlotId, - mapOf( - slotId1 to listOf(affordanceId1, affordanceId3), - slotId2 to listOf(affordanceId2), - ) - ) + job.cancel() + } - underTest.setSelections( - slotId = slotId1, - affordanceIds = listOf(affordanceId3), - ) - assertSelections( - affordanceIdsBySlotId, - mapOf( - slotId1 to listOf(affordanceId3), - slotId2 to listOf(affordanceId2), - ) - ) - - underTest.setSelections( - slotId = slotId2, - affordanceIds = listOf(), - ) - assertSelections( - affordanceIdsBySlotId, - mapOf( - slotId1 to listOf(affordanceId3), - slotId2 to listOf(), - ) - ) - - job.cancel() - } - - private suspend fun assertSelections( + private fun assertSelections( observed: Map>?, expected: Map>, ) { assertThat(underTest.getSelections()).isEqualTo(expected) assertThat(observed).isEqualTo(expected) } - - companion object { - private val IMMEDIATE = Dispatchers.Main.immediate - } } 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 dceb492af2ed0..a95f788b1ee91 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 @@ -25,6 +25,11 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation +import com.android.systemui.settings.FakeUserTracker +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.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -36,6 +41,8 @@ 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 @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -55,8 +62,21 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { KeyguardQuickAffordanceRepository( appContext = context, scope = CoroutineScope(IMMEDIATE), - backgroundDispatcher = IMMEDIATE, - selectionManager = KeyguardQuickAffordanceSelectionManager(), + selectionManager = + KeyguardQuickAffordanceSelectionManager( + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = FakeUserTracker(), + ), 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 737f242247273..3e37459d8eeb9 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 @@ -36,8 +36,11 @@ import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepo import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker 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.mockito.whenever @@ -50,6 +53,8 @@ import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameter import org.junit.runners.Parameterized.Parameters +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.same import org.mockito.Mock @@ -201,7 +206,6 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var keyguardStateController: KeyguardStateController - @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var animationController: ActivityLaunchAnimator.Controller @Mock private lateinit var expandable: Expandable @@ -214,12 +218,14 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { @JvmField @Parameter(3) var needsToUnlockFirst: Boolean = false @JvmField @Parameter(4) var startActivity: Boolean = false private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig + private lateinit var userTracker: UserTracker @Before fun setUp() { MockitoAnnotations.initMocks(this) whenever(expandable.activityLaunchController()).thenReturn(animationController) + userTracker = FakeUserTracker() homeControls = FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS) val quickAccessWallet = @@ -232,8 +238,21 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { KeyguardQuickAffordanceRepository( appContext = context, scope = CoroutineScope(IMMEDIATE), - backgroundDispatcher = IMMEDIATE, - selectionManager = KeyguardQuickAffordanceSelectionManager(), + selectionManager = + KeyguardQuickAffordanceSelectionManager( + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ), configs = setOf(homeControls, quickAccessWallet, qrCodeScanner), ) underTest = @@ -319,7 +338,6 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { needStrongAuthAfterBoot: Boolean = true, keyguardIsUnlocked: Boolean = false, ) { - whenever(userTracker.userHandle).thenReturn(mock()) whenever(lockPatternUtils.getStrongAuthForUser(any())) .thenReturn( if (needStrongAuthAfterBoot) { 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 ffcf832b95aec..f887bf93de8d1 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 @@ -35,9 +35,11 @@ import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAff import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots 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.google.common.truth.Truth.assertThat @@ -53,6 +55,8 @@ 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 @@ -94,8 +98,21 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceRepository( appContext = context, scope = CoroutineScope(IMMEDIATE), - backgroundDispatcher = IMMEDIATE, - selectionManager = KeyguardQuickAffordanceSelectionManager(), + selectionManager = + KeyguardQuickAffordanceSelectionManager( + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ), configs = setOf(homeControls, quickAccessWallet, qrCodeScanner), ) featureFlags = 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 fa2ac46f46d20..03e6ccb6fabe2 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 @@ -38,8 +38,10 @@ import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAff import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker 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.google.common.truth.Truth.assertThat @@ -56,6 +58,7 @@ 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.Mockito import org.mockito.Mockito.verifyZeroInteractions @@ -119,8 +122,21 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { KeyguardQuickAffordanceRepository( appContext = context, scope = CoroutineScope(IMMEDIATE), - backgroundDispatcher = IMMEDIATE, - selectionManager = KeyguardQuickAffordanceSelectionManager(), + selectionManager = + KeyguardQuickAffordanceSelectionManager( + userFileManager = + mock().apply { + whenever( + getSharedPreferences( + anyString(), + anyInt(), + anyInt(), + ) + ) + .thenReturn(FakeSharedPreferences()) + }, + userTracker = userTracker, + ), configs = setOf( homeControlsQuickAffordanceConfig,