Merge "Fix bug with home panel dream" into main
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorKosmos.kt
index efccf7a..e4ce6cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorKosmos.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorKosmos.kt
@@ -17,7 +17,7 @@
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
-import com.android.systemui.controls.panels.AuthorizedPanelsRepository
+import com.android.systemui.controls.panels.authorizedPanelsRepository
import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor
import com.android.systemui.kosmos.Kosmos
@@ -38,4 +38,3 @@
val Kosmos.controlsComponent by Kosmos.Fixture<ControlsComponent> { mock() }
val Kosmos.controlsListingController by Kosmos.Fixture<ControlsListingController> { mock() }
-val Kosmos.authorizedPanelsRepository by Kosmos.Fixture<AuthorizedPanelsRepository> { mock() }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt
index ce74a90..6ad32cc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt
@@ -27,13 +27,14 @@
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
-import com.android.systemui.controls.panels.FakeSelectedComponentRepository
import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.authorizedPanelsRepository
import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
@@ -41,6 +42,9 @@
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -48,6 +52,7 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class HomeControlsComponentInteractorTest : SysuiTestCase() {
@@ -59,20 +64,20 @@
private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
private lateinit var underTest: HomeControlsComponentInteractor
private lateinit var userRepository: FakeUserRepository
- private lateinit var selectedComponentRepository: FakeSelectedComponentRepository
+ private lateinit var selectedComponentRepository: SelectedComponentRepository
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- userRepository = kosmos.fakeUserRepository
- userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER))
controlsComponent = kosmos.controlsComponent
authorizedPanelsRepository = kosmos.authorizedPanelsRepository
controlsListingController = kosmos.controlsListingController
selectedComponentRepository = kosmos.selectedComponentRepository
- selectedComponentRepository.setCurrentUserHandle(PRIMARY_USER.userHandle)
+ userRepository = kosmos.fakeUserRepository
+ userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER))
+
whenever(controlsComponent.getControlsListingController())
.thenReturn(Optional.of(controlsListingController))
@@ -90,14 +95,13 @@
fun testPanelComponentReturnsComponentNameForSelectedItemByUser() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ setActiveUser(PRIMARY_USER)
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE))
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_PANEL)
val actualValue by collectLastValue(underTest.panelComponent)
assertThat(actualValue).isNull()
runServicesUpdate()
- assertThat(actualValue).isEqualTo(TEST_COMPONENT_PANEL)
+ assertThat(actualValue).isEqualTo(TEST_COMPONENT)
}
}
@@ -105,16 +109,15 @@
fun testPanelComponentReturnsComponentNameAsInitialValueWithoutServiceUpdate() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ setActiveUser(PRIMARY_USER)
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE))
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_PANEL)
whenever(controlsListingController.getCurrentServices())
.thenReturn(
- listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true))
+ listOf(ControlsServiceInfo(TEST_COMPONENT, "panel", hasPanel = true))
)
val actualValue by collectLastValue(underTest.panelComponent)
- assertThat(actualValue).isEqualTo(TEST_COMPONENT_PANEL)
+ assertThat(actualValue).isEqualTo(TEST_COMPONENT)
}
}
@@ -122,9 +125,8 @@
fun testPanelComponentReturnsNullForHomeControlsThatDoesNotSupportPanel() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ setActiveUser(PRIMARY_USER)
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE))
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_NON_PANEL)
val actualValue by collectLastValue(underTest.panelComponent)
assertThat(actualValue).isNull()
@@ -137,8 +139,8 @@
fun testPanelComponentReturnsNullWhenPanelIsUnauthorized() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels()).thenReturn(setOf())
- userRepository.setSelectedUserInfo(PRIMARY_USER)
+ setActiveUser(PRIMARY_USER)
+ authorizedPanelsRepository.removeAuthorizedPanels(setOf(TEST_PACKAGE))
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_PANEL)
val actualValue by collectLastValue(underTest.panelComponent)
assertThat(actualValue).isNull()
@@ -151,17 +153,24 @@
fun testPanelComponentReturnsComponentNameForDifferentUsers() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
- userRepository.setSelectedUserInfo(ANOTHER_USER)
+ val actualValue by collectLastValue(underTest.panelComponent)
+
+ // Secondary user has non-panel selected.
+ setActiveUser(ANOTHER_USER)
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_NON_PANEL)
- selectedComponentRepository.setCurrentUserHandle(ANOTHER_USER.userHandle)
+
+ // Primary user has panel selected.
+ setActiveUser(PRIMARY_USER)
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE))
selectedComponentRepository.setSelectedComponent(TEST_SELECTED_COMPONENT_PANEL)
- val actualValue by collectLastValue(underTest.panelComponent)
- assertThat(actualValue).isNull()
runServicesUpdate()
- assertThat(actualValue).isEqualTo(TEST_COMPONENT_PANEL)
+ assertThat(actualValue).isEqualTo(TEST_COMPONENT)
+
+ // Back to secondary user, should be null.
+ setActiveUser(ANOTHER_USER)
+ runServicesUpdate()
+ assertThat(actualValue).isNull()
}
}
@@ -169,8 +178,7 @@
fun testPanelComponentReturnsNullWhenControlsComponentReturnsNullForListingController() =
with(kosmos) {
testScope.runTest {
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE))
whenever(controlsComponent.getControlsListingController())
.thenReturn(Optional.empty())
userRepository.setSelectedUserInfo(PRIMARY_USER)
@@ -182,11 +190,17 @@
private fun runServicesUpdate(hasPanelBoolean: Boolean = true) {
val listings =
- listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = hasPanelBoolean))
+ listOf(ControlsServiceInfo(TEST_COMPONENT, "panel", hasPanel = hasPanelBoolean))
val callback = withArgCaptor { verify(controlsListingController).addCallback(capture()) }
callback.onServicesUpdated(listings)
}
+ private suspend fun TestScope.setActiveUser(user: UserInfo) {
+ userRepository.setSelectedUserInfo(user)
+ kosmos.fakeUserTracker.set(listOf(user), 0)
+ runCurrent()
+ }
+
private fun ControlsServiceInfo(
componentName: ComponentName,
label: CharSequence,
@@ -237,19 +251,9 @@
)
private const val TEST_PACKAGE = "pkg"
private val TEST_COMPONENT = ComponentName(TEST_PACKAGE, "service")
- private const val TEST_PACKAGE_PANEL = "pkg.panel"
- private val TEST_COMPONENT_PANEL = ComponentName(TEST_PACKAGE_PANEL, "service")
private val TEST_SELECTED_COMPONENT_PANEL =
- SelectedComponentRepository.SelectedComponent(
- TEST_PACKAGE_PANEL,
- TEST_COMPONENT_PANEL,
- true
- )
+ SelectedComponentRepository.SelectedComponent(TEST_PACKAGE, TEST_COMPONENT, true)
private val TEST_SELECTED_COMPONENT_NON_PANEL =
- SelectedComponentRepository.SelectedComponent(
- TEST_PACKAGE_PANEL,
- TEST_COMPONENT_PANEL,
- false
- )
+ SelectedComponentRepository.SelectedComponent(TEST_PACKAGE, TEST_COMPONENT, false)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamStartableTest.kt
index 6610e70..87b1bbb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamStartableTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.authorizedPanelsRepository
import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -84,8 +85,7 @@
userRepository.setUserInfos(listOf(PRIMARY_USER))
- whenever(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(TEST_PACKAGE_PANEL))
+ authorizedPanelsRepository.addAuthorizedPanels(setOf(TEST_PACKAGE_PANEL))
whenever(controlsComponent.getControlsListingController())
.thenReturn(Optional.of(controlsListingController))
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
index 85aeb4d..0e9b32f 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt
@@ -28,8 +28,8 @@
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.settings.UserFileManager
-import com.android.systemui.settings.UserFileManagerExt.observeSharedPreferences
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -97,8 +97,8 @@
}
private fun observeCtaDismissState(user: UserInfo): Flow<Boolean> =
- userFileManager
- .observeSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, user.id)
+ getSharedPrefsForUser(user)
+ .observe(CTA_DISMISSED_STATE)
// Emit at the start of collection to ensure we get an initial value
.onStart { emit(Unit) }
.map { getCtaDismissedState() }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
index ae9c37a..b35bec4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt
@@ -17,11 +17,16 @@
package com.android.systemui.controls.panels
+import android.os.UserHandle
+import kotlinx.coroutines.flow.Flow
+
/**
* Repository for keeping track of which packages the panel has authorized to show control panels
* (embedded activity).
*/
interface AuthorizedPanelsRepository {
+ /** Exposes the authorized panels as a [Flow] for subscribing to updates */
+ fun observeAuthorizedPanels(user: UserHandle): Flow<Set<String>>
/** A set of package names that the user has previously authorized to show panels. */
fun getAuthorizedPanels(): Set<String>
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
index 4e935df..7c2dae3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt
@@ -19,11 +19,16 @@
import android.content.Context
import android.content.SharedPreferences
+import android.os.UserHandle
import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
class AuthorizedPanelsRepositoryImpl
@Inject
@@ -33,19 +38,24 @@
private val userTracker: UserTracker,
) : AuthorizedPanelsRepository {
+ override fun observeAuthorizedPanels(user: UserHandle): Flow<Set<String>> {
+ val prefs = instantiateSharedPrefs(user)
+ return prefs.observe(KEY).onStart { emit(Unit) }.map { getAuthorizedPanelsInternal(prefs) }
+ }
+
override fun getAuthorizedPanels(): Set<String> {
- return getAuthorizedPanelsInternal(instantiateSharedPrefs())
+ return getAuthorizedPanelsInternal(instantiateSharedPrefs(userTracker.userHandle))
}
override fun getPreferredPackages(): Set<String> =
context.resources.getStringArray(R.array.config_controlsPreferredPackages).toSet()
override fun addAuthorizedPanels(packageNames: Set<String>) {
- addAuthorizedPanelsInternal(instantiateSharedPrefs(), packageNames)
+ addAuthorizedPanelsInternal(instantiateSharedPrefs(userTracker.userHandle), packageNames)
}
override fun removeAuthorizedPanels(packageNames: Set<String>) {
- with(instantiateSharedPrefs()) {
+ with(instantiateSharedPrefs(userTracker.userHandle)) {
val currentSet = getAuthorizedPanelsInternal(this)
edit().putStringSet(KEY, currentSet - packageNames).apply()
}
@@ -63,12 +73,12 @@
sharedPreferences.edit().putStringSet(KEY, currentSet + packageNames).apply()
}
- private fun instantiateSharedPrefs(): SharedPreferences {
+ private fun instantiateSharedPrefs(user: UserHandle): SharedPreferences {
val sharedPref =
userFileManager.getSharedPreferences(
DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
Context.MODE_PRIVATE,
- userTracker.userId,
+ user.identifier,
)
// We should add default packages when we've never run this
diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
index 0baa81a..9be04940 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt
@@ -20,21 +20,18 @@
import android.content.Context
import android.content.SharedPreferences
import android.os.UserHandle
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.flags.FeatureFlags
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import com.android.systemui.util.kotlin.SharedPreferencesExt.observe
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
@SysUISingleton
@@ -43,9 +40,7 @@
constructor(
private val userFileManager: UserFileManager,
private val userTracker: UserTracker,
- private val featureFlags: FeatureFlags,
- @Background private val bgDispatcher: CoroutineDispatcher,
- @Application private val applicationScope: CoroutineScope
+ @Background private val bgDispatcher: CoroutineDispatcher
) : SelectedComponentRepository {
private companion object {
@@ -66,22 +61,11 @@
override fun selectedComponentFlow(
userHandle: UserHandle
): Flow<SelectedComponentRepository.SelectedComponent?> {
- return conflatedCallbackFlow {
- val sharedPreferencesByUserId = getSharedPreferencesForUser(userHandle.identifier)
- val listener =
- SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
- applicationScope.launch(bgDispatcher) {
- if (key == PREF_COMPONENT) {
- trySend(getSelectedComponent(userHandle))
- }
- }
- }
- sharedPreferencesByUserId.registerOnSharedPreferenceChangeListener(listener)
- send(getSelectedComponent(userHandle))
- awaitClose {
- sharedPreferencesByUserId.unregisterOnSharedPreferenceChangeListener(listener)
- }
- }
+ val prefs = getSharedPreferencesForUser(userHandle.identifier)
+ return prefs
+ .observe(PREF_COMPONENT)
+ .onStart { emit(Unit) }
+ .map { getSelectedComponent(userHandle) }
.flowOn(bgDispatcher)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt
index 91e0547..0cab10db 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt
@@ -47,24 +47,30 @@
@Inject
constructor(
private val selectedComponentRepository: SelectedComponentRepository,
- private val controlsComponent: ControlsComponent,
- private val authorizedPanelsRepository: AuthorizedPanelsRepository,
+ controlsComponent: ControlsComponent,
+ authorizedPanelsRepository: AuthorizedPanelsRepository,
userRepository: UserRepository,
@Background private val bgScope: CoroutineScope
) {
- private val controlsListingController =
+ private val controlsListingController: ControlsListingController? =
controlsComponent.getControlsListingController().getOrNull()
/** Gets the current user's selected panel, or null if there isn't one */
- private val selectedItem: Flow<SelectedComponentRepository.SelectedComponent?> =
+ private val selectedPanel: Flow<SelectedComponentRepository.SelectedComponent?> =
userRepository.selectedUserInfo
.flatMapLatest { user ->
selectedComponentRepository.selectedComponentFlow(user.userHandle)
}
.map { if (it?.isPanel == true) it else null }
- /** Gets all the available panels which are authorized by the user */
- private fun allPanelItem(): Flow<List<PanelComponent>> {
+ /** Gets the current user's authorized panels */
+ private val allAuthorizedPanels: Flow<Set<String>> =
+ userRepository.selectedUserInfo.flatMapLatest { user ->
+ authorizedPanelsRepository.observeAuthorizedPanels(user.userHandle)
+ }
+
+ /** Gets all the available services from [ControlsListingController] */
+ private fun allAvailableServices(): Flow<List<ControlsServiceInfo>> {
if (controlsListingController == null) {
return emptyFlow()
}
@@ -79,26 +85,38 @@
awaitClose { controlsListingController.removeCallback(listener) }
}
.onStart { emit(controlsListingController.getCurrentServices()) }
- .map { serviceInfos ->
- val authorizedPanels = authorizedPanelsRepository.getAuthorizedPanels()
- serviceInfos.mapNotNull {
- val panelActivity = it.panelActivity
- if (it.componentName.packageName in authorizedPanels && panelActivity != null) {
- PanelComponent(it.componentName, panelActivity)
- } else {
- null
- }
+ }
+
+ /** Gets all panels which are available and authorized by the user */
+ private val allAvailableAndAuthorizedPanels: Flow<List<PanelComponent>> =
+ combine(
+ allAvailableServices(),
+ allAuthorizedPanels,
+ ) { serviceInfos, authorizedPanels ->
+ serviceInfos.mapNotNull {
+ val panelActivity = it.panelActivity
+ if (it.componentName.packageName in authorizedPanels && panelActivity != null) {
+ PanelComponent(it.componentName, panelActivity)
+ } else {
+ null
}
}
- }
+ }
+
val panelComponent: StateFlow<ComponentName?> =
- combine(allPanelItem(), selectedItem) { items, selected ->
+ combine(
+ allAvailableAndAuthorizedPanels,
+ selectedPanel,
+ ) { panels, selected ->
val item =
- items.firstOrNull { it.componentName == selected?.componentName }
- ?: items.firstOrNull()
+ panels.firstOrNull { it.componentName == selected?.componentName }
+ ?: panels.firstOrNull()
item?.panelActivity
}
.stateIn(bgScope, SharingStarted.WhileSubscribed(), null)
- data class PanelComponent(val componentName: ComponentName, val panelActivity: ComponentName)
+ private data class PanelComponent(
+ val componentName: ComponentName,
+ val panelActivity: ComponentName,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerExt.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerExt.kt
deleted file mode 100644
index b09bfe2..0000000
--- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerExt.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.settings
-
-import android.annotation.UserIdInt
-import android.content.Context
-import android.content.SharedPreferences
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-
-/** Extension functions for [UserFileManager]. */
-object UserFileManagerExt {
-
- /** Returns a flow of [Unit] that is invoked each time the shared preference is updated. */
- fun UserFileManager.observeSharedPreferences(
- fileName: String,
- @Context.PreferencesMode mode: Int,
- @UserIdInt userId: Int
- ): Flow<Unit> = conflatedCallbackFlow {
- val sharedPrefs = getSharedPreferences(fileName, mode, userId)
-
- val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, _ -> trySend(Unit) }
-
- sharedPrefs.registerOnSharedPreferenceChangeListener(listener)
- awaitClose { sharedPrefs.unregisterOnSharedPreferenceChangeListener(listener) }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt
new file mode 100644
index 0000000..ab6a37b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import android.content.SharedPreferences
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.mapNotNull
+
+object SharedPreferencesExt {
+ /**
+ * Returns a flow of [Unit] that is invoked each time shared preference is updated.
+ *
+ * @param key Optional key to limit updates to a particular key.
+ */
+ fun SharedPreferences.observe(key: String? = null): Flow<Unit> =
+ conflatedCallbackFlow {
+ val listener =
+ SharedPreferences.OnSharedPreferenceChangeListener { _, key -> trySend(key) }
+ registerOnSharedPreferenceChangeListener(listener)
+ awaitClose { unregisterOnSharedPreferenceChangeListener(listener) }
+ }
+ .mapNotNull { changedKey -> if ((key ?: changedKey) == changedKey) Unit else null }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index c98d537..de455f63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -34,11 +34,12 @@
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
-import com.android.systemui.controls.panels.FakeSelectedComponentRepository
+import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -69,12 +70,13 @@
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import java.io.File
-import java.util.*
+import java.util.Optional
import java.util.function.Consumer
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ControlsControllerImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
@Mock
private lateinit var uiController: ControlsUiController
@@ -109,8 +111,6 @@
private lateinit var listingCallbackCaptor:
ArgumentCaptor<ControlsListingController.ControlsListingCallback>
- private val preferredPanelRepository = FakeSelectedComponentRepository()
-
private lateinit var delayableExecutor: FakeExecutor
private lateinit var controller: ControlsControllerImpl
private lateinit var canceller: DidRunRunnable
@@ -171,7 +171,7 @@
wrapper,
delayableExecutor,
uiController,
- preferredPanelRepository,
+ kosmos.selectedComponentRepository,
bindingController,
listingController,
userFileManager,
@@ -225,7 +225,7 @@
mContext,
delayableExecutor,
uiController,
- preferredPanelRepository,
+ kosmos.selectedComponentRepository,
bindingController,
listingController,
userFileManager,
@@ -245,7 +245,7 @@
mContext,
delayableExecutor,
uiController,
- preferredPanelRepository,
+ kosmos.selectedComponentRepository,
bindingController,
listingController,
userFileManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
index 4828ba3..18ce4a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt
@@ -18,36 +18,40 @@
package com.android.systemui.controls.panels
import android.content.SharedPreferences
+import android.content.pm.UserInfo
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserFileManager
-import com.android.systemui.settings.UserTracker
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.testKosmos
import com.android.systemui.util.FakeSharedPreferences
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.io.File
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
- @Mock private lateinit var userTracker: UserTracker
+ private lateinit var userTracker: FakeUserTracker
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
mContext.orCreateTestableResources.addOverride(
R.array.config_controlsPreferredPackages,
arrayOf<String>()
)
- whenever(userTracker.userId).thenReturn(0)
+ userTracker = kosmos.fakeUserTracker.apply { set(listOf(PRIMARY_USER, SECONDARY_USER), 0) }
}
@Test
@@ -91,7 +95,7 @@
val repository = createRepository(fileManager)
assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
- whenever(userTracker.userId).thenReturn(1)
+ userTracker.set(listOf(SECONDARY_USER), 0)
assertThat(repository.getAuthorizedPanels()).isEmpty()
}
@@ -127,6 +131,51 @@
assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty()
}
+ @Test
+ fun observeAuthorizedPanels() =
+ testScope.runTest {
+ val sharedPrefs = FakeSharedPreferences()
+ val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
+ val repository = createRepository(fileManager)
+
+ val authorizedPanels by
+ collectLastValue(repository.observeAuthorizedPanels(PRIMARY_USER.userHandle))
+ assertThat(authorizedPanels).isEmpty()
+
+ repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
+ assertThat(authorizedPanels).containsExactly(TEST_PACKAGE)
+
+ repository.removeAuthorizedPanels(setOf(TEST_PACKAGE))
+ assertThat(authorizedPanels).isEmpty()
+ }
+
+ @Test
+ fun observeAuthorizedPanelsForAnotherUser() =
+ testScope.runTest {
+ val fileManager =
+ FakeUserFileManager(
+ mapOf(
+ 0 to FakeSharedPreferences(),
+ 1 to FakeSharedPreferences(),
+ )
+ )
+ val repository = createRepository(fileManager)
+
+ val authorizedPanels by
+ collectLastValue(repository.observeAuthorizedPanels(SECONDARY_USER.userHandle))
+ assertThat(authorizedPanels).isEmpty()
+
+ // Primary user is active, add authorized panels.
+ repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
+ assertThat(authorizedPanels).isEmpty()
+
+ // Make secondary user active and add authorized panels again.
+ userTracker.set(listOf(PRIMARY_USER, SECONDARY_USER), 1)
+ assertThat(authorizedPanels).isEmpty()
+ repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
+ assertThat(authorizedPanels).containsExactly(TEST_PACKAGE)
+ }
+
private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl {
return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker)
}
@@ -153,5 +202,9 @@
private const val FILE_NAME = "controls_prefs"
private const val KEY = "authorized_panels"
private const val TEST_PACKAGE = "package"
+ private val PRIMARY_USER =
+ UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)
+ private val SECONDARY_USER =
+ UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
index b463adf..a7e7ba9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt
@@ -23,8 +23,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.settings.UserFileManager
@@ -74,7 +72,6 @@
@Mock private lateinit var userTracker: UserTracker
private lateinit var userFileManager: UserFileManager
- private val featureFlags = FakeFeatureFlags()
// under test
private lateinit var repository: SelectedComponentRepository
@@ -95,11 +92,9 @@
)
repository =
SelectedComponentRepositoryImpl(
- userFileManager,
- userTracker,
- featureFlags,
+ userFileManager = userFileManager,
+ userTracker = userTracker,
bgDispatcher = testDispatcher,
- applicationScope = applicationCoroutineScope
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
index bcef67e..94ea799 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt
@@ -38,8 +38,8 @@
import com.android.systemui.controls.dagger.ControlsComponent
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
-import com.android.systemui.controls.panels.FakeSelectedComponentRepository
import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
@@ -87,7 +87,7 @@
@Mock private lateinit var userManager: UserManager
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
- private lateinit var preferredPanelsRepository: FakeSelectedComponentRepository
+ private lateinit var preferredPanelsRepository: SelectedComponentRepository
private lateinit var fakeExecutor: FakeExecutor
@@ -99,7 +99,7 @@
whenever(userTracker.userHandle).thenReturn(UserHandle.of(1))
fakeExecutor = FakeExecutor(FakeSystemClock())
- preferredPanelsRepository = FakeSelectedComponentRepository()
+ preferredPanelsRepository = kosmos.selectedComponentRepository
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index 36ae0c7..8f3813d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -43,8 +43,8 @@
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
-import com.android.systemui.controls.panels.FakeSelectedComponentRepository
import com.android.systemui.controls.panels.SelectedComponentRepository
+import com.android.systemui.controls.panels.selectedComponentRepository
import com.android.systemui.controls.settings.FakeControlsSettingsRepository
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
@@ -53,6 +53,7 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.testKosmos
import com.android.systemui.util.FakeSystemUIDialogController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -85,6 +86,8 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class ControlsUiControllerImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+
@Mock lateinit var controlsController: ControlsController
@Mock lateinit var controlsListingController: ControlsListingController
@Mock lateinit var controlActionCoordinator: ControlActionCoordinator
@@ -100,7 +103,7 @@
@Mock lateinit var packageManager: PackageManager
@Mock lateinit var systemUIDialogFactory: SystemUIDialog.Factory
- private val preferredPanelRepository = FakeSelectedComponentRepository()
+ private val preferredPanelRepository = kosmos.selectedComponentRepository
private lateinit var fakeDialogController: FakeSystemUIDialogController
private val uiExecutor = FakeExecutor(FakeSystemClock())
private val bgExecutor = FakeExecutor(FakeSystemClock())
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryKosmos.kt
new file mode 100644
index 0000000..109e113
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.settings.fakeUserFileManager
+import com.android.systemui.settings.fakeUserTracker
+
+var Kosmos.authorizedPanelsRepository: AuthorizedPanelsRepository by
+ Kosmos.Fixture {
+ AuthorizedPanelsRepositoryImpl(applicationContext, fakeUserFileManager, fakeUserTracker)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt
deleted file mode 100644
index a231212..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.controls.panels
-
-import android.os.UserHandle
-import com.android.systemui.kosmos.Kosmos
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-
-class FakeSelectedComponentRepository : SelectedComponentRepository {
- private var shouldAddDefaultPanel: Boolean = true
- private val _selectedComponentFlows =
- mutableMapOf<UserHandle, MutableStateFlow<SelectedComponentRepository.SelectedComponent?>>()
- private var currentUserHandle: UserHandle = UserHandle.of(0)
-
- override fun selectedComponentFlow(
- userHandle: UserHandle
- ): Flow<SelectedComponentRepository.SelectedComponent?> {
- // Return an existing flow for the user or create a new one
- return _selectedComponentFlows.getOrPut(getUserHandle(userHandle)) {
- MutableStateFlow(null)
- }
- }
-
- override fun getSelectedComponent(
- userHandle: UserHandle
- ): SelectedComponentRepository.SelectedComponent? {
- return _selectedComponentFlows[getUserHandle(userHandle)]?.value
- }
-
- override fun setSelectedComponent(
- selectedComponent: SelectedComponentRepository.SelectedComponent
- ) {
- val flow = _selectedComponentFlows.getOrPut(currentUserHandle) { MutableStateFlow(null) }
- flow.value = selectedComponent
- }
-
- override fun removeSelectedComponent() {
- _selectedComponentFlows[currentUserHandle]?.value = null
- }
- override fun shouldAddDefaultComponent(): Boolean = shouldAddDefaultPanel
-
- override fun setShouldAddDefaultComponent(shouldAdd: Boolean) {
- shouldAddDefaultPanel = shouldAdd
- }
-
- fun setCurrentUserHandle(userHandle: UserHandle) {
- currentUserHandle = userHandle
- }
- private fun getUserHandle(userHandle: UserHandle): UserHandle {
- return if (userHandle == UserHandle.CURRENT) {
- currentUserHandle
- } else {
- userHandle
- }
- }
-}
-
-val Kosmos.selectedComponentRepository by
- Kosmos.Fixture<FakeSelectedComponentRepository> { FakeSelectedComponentRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/SelectedComponentRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/SelectedComponentRepositoryKosmos.kt
new file mode 100644
index 0000000..ee5b7e5
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/controls/panels/SelectedComponentRepositoryKosmos.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.panels
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.settings.fakeUserFileManager
+import com.android.systemui.settings.fakeUserTracker
+
+var Kosmos.selectedComponentRepository: SelectedComponentRepository by
+ Kosmos.Fixture {
+ SelectedComponentRepositoryImpl(fakeUserFileManager, fakeUserTracker, testDispatcher)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserFileManager.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserFileManager.kt
new file mode 100644
index 0000000..207c3f7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserFileManager.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.settings
+
+import android.content.SharedPreferences
+import com.android.systemui.util.FakeSharedPreferences
+import java.io.File
+
+class FakeUserFileManager : UserFileManager {
+ private val sharedPreferences = mutableMapOf<SharedPrefKey, FakeSharedPreferences>()
+
+ override fun getFile(fileName: String, userId: Int): File {
+ throw UnsupportedOperationException("getFile not implemented in fake")
+ }
+
+ override fun getSharedPreferences(fileName: String, mode: Int, userId: Int): SharedPreferences {
+ val key = SharedPrefKey(fileName, mode, userId)
+ return sharedPreferences.getOrPut(key) { FakeSharedPreferences() }
+ }
+
+ private data class SharedPrefKey(val fileName: String, val mode: Int, val userId: Int)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserFileManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserFileManagerKosmos.kt
new file mode 100644
index 0000000..4d7a40a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/UserFileManagerKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.settings
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeUserFileManager by Kosmos.Fixture { FakeUserFileManager() }
+var Kosmos.userFileManager: UserFileManager by Kosmos.Fixture { fakeUserFileManager }