diff options
| author | 2025-02-06 07:47:38 -0800 | |
|---|---|---|
| committer | 2025-02-06 07:47:38 -0800 | |
| commit | e80f1b9a275793715dd7279e2ab352ed56e72e94 (patch) | |
| tree | 00447a339603e31870b4a1172a18732e8108bb88 | |
| parent | 644ed4e9944e6be5685d7750552e5b78a566b10b (diff) | |
| parent | b02dd916fc279fbf7a41100c87e334abb94bf30d (diff) | |
Merge "Upgrade path for small/large tiles" into main
11 files changed, 306 insertions, 17 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt index 4dcbdfae6d4a..264eda5a07eb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.data.repository.userRepository import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -104,6 +105,114 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { } } + @Test + fun setInitialTilesFromSettings_noLargeTiles_tilesSet() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + val tiles = setOf("tileA", "tileB").toTileSpecs() + + assertThat(getSharedPreferences().contains(LARGE_TILES_SPECS_KEY)).isFalse() + + underTest.setInitialLargeTilesSpecs(tiles, PRIMARY_USER_ID) + + assertThat(largeTiles).isEqualTo(tiles) + } + } + + @Test + fun setInitialTilesFromSettings_alreadyLargeTiles_tilesNotSet() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + setLargeTilesSpecsInSharedPreferences(setOf("tileC")) + + underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + + assertThat(largeTiles).isEqualTo(setOf("tileC").toTileSpecs()) + } + } + + @Test + fun setInitialTilesFromSettings_emptyLargeTiles_tilesNotSet() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + setLargeTilesSpecsInSharedPreferences(emptySet()) + + underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + + assertThat(largeTiles).isEmpty() + } + } + + @Test + fun setInitialTilesFromSettings_nonCurrentUser_tilesSetForCorrectUser() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + + underTest.setInitialLargeTilesSpecs(setOf("tileA").toTileSpecs(), ANOTHER_USER_ID) + + assertThat(largeTiles).isEqualTo(defaultLargeTilesRepository.defaultLargeTiles) + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + assertThat(largeTiles).isEqualTo(setOf("tileA").toTileSpecs()) + } + } + + @Test + fun setInitialTiles_afterDefaultRead_noSetOnRepository_initialTilesCorrect() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + + val currentLargeTiles = underTest.largeTilesSpecs.first() + + assertThat(currentLargeTiles).isNotEmpty() + + val tiles = setOf("tileA", "tileB") + underTest.setInitialLargeTilesSpecs(tiles.toTileSpecs(), PRIMARY_USER_ID) + + assertThat(largeTiles).isEqualTo(tiles.toTileSpecs()) + } + } + + @Test + fun setInitialTiles_afterDefaultRead_largeTilesSetOnRepository_initialTilesCorrect() = + with(kosmos) { + testScope.runTest { + val largeTiles by collectLastValue(underTest.largeTilesSpecs) + fakeUserRepository.setUserInfos(USERS) + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + + val currentLargeTiles = underTest.largeTilesSpecs.first() + + assertThat(currentLargeTiles).isNotEmpty() + + underTest.setLargeTilesSpecs(setOf(TileSpec.create("tileC"))) + + val tiles = setOf("tileA", "tileB") + underTest.setInitialLargeTilesSpecs(tiles.toTileSpecs(), PRIMARY_USER_ID) + + assertThat(largeTiles).isEqualTo(setOf(TileSpec.create("tileC"))) + } + } + private fun getSharedPreferences(): SharedPreferences = with(kosmos) { return userFileManager.getSharedPreferences( @@ -121,20 +230,11 @@ class QSPreferencesRepositoryTest : SysuiTestCase() { return getSharedPreferences().getStringSet(LARGE_TILES_SPECS_KEY, emptySet())!! } - private fun setShowLabelsInSharedPreferences(value: Boolean) { - getSharedPreferences().edit().putBoolean(ICON_LABELS_KEY, value).apply() - } - - private fun getShowLabelsFromSharedPreferences(defaultValue: Boolean): Boolean { - return getSharedPreferences().getBoolean(ICON_LABELS_KEY, defaultValue) - } - private fun Set<String>.toTileSpecs(): Set<TileSpec> { return map { TileSpec.create(it) }.toSet() } companion object { - private const val ICON_LABELS_KEY = "show_icon_labels" private const val LARGE_TILES_SPECS_KEY = "large_tiles_specs" private const val PRIMARY_USER_ID = 0 private val PRIMARY_USER = UserInfo(PRIMARY_USER_ID, "user 0", UserInfo.FLAG_MAIN) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt index 88e3951cdf92..4b8cd3742bff 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt @@ -22,12 +22,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.res.R import com.android.systemui.retail.data.repository.FakeRetailModeRepository import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -90,6 +92,7 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { logger, retailModeRepository, userTileSpecRepositoryFactory, + testScope.backgroundScope, ) } @@ -231,6 +234,40 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() { assertThat(tiles!!).containsExactlyElementsIn(DEFAULT_TILES.toTileSpecs()) } + @Test + fun readSettingsStored_emittedForUser() = + testScope.runTest { + val startingTiles = "a,b" + val userId = 10 + storeTilesForUser(startingTiles, userId) + + val tiles by collectLastValue(underTest.tilesSpecs(userId)) + val tilesRead by collectLastValue(underTest.tilesReadFromSetting.consumeAsFlow()) + + assertThat(tilesRead).isEqualTo(startingTiles.toTileSpecs().toSet() to userId) + } + + @Test + fun readSettingsStored_multipleUsers() = + testScope.runTest { + val startingTiles10 = "a" + val startingTiles11 = "b,c" + storeTilesForUser(startingTiles10, 10) + storeTilesForUser(startingTiles11, 11) + + val tiles10 by collectLastValue(underTest.tilesSpecs(10)) + val tiles11 by collectLastValue(underTest.tilesSpecs(11)) + + val tilesRead by collectValues(underTest.tilesReadFromSetting.consumeAsFlow()) + + assertThat(tilesRead).hasSize(2) + assertThat(tilesRead) + .containsExactly( + startingTiles10.toTileSpecs().toSet() to 10, + startingTiles11.toTileSpecs().toSet() to 11, + ) + } + private fun TestScope.storeTilesForUser(specs: String, forUser: Int) { secureSettings.putStringForUser(SETTING, specs, forUser) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt index 502e179f62ec..1945f750efaf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt @@ -7,11 +7,13 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.qs.pipeline.data.model.RestoreData +import com.android.systemui.qs.pipeline.data.repository.UserTileSpecRepositoryTest.Companion.toTilesSet import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -312,11 +314,7 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { runCurrent() val restoreData = - RestoreData( - restoredSpecs.toTileSpecs(), - restoredAutoAdded.toTilesSet(), - USER, - ) + RestoreData(restoredSpecs.toTileSpecs(), restoredAutoAdded.toTilesSet(), USER) underTest.reconcileRestore(restoreData, autoAddedBeforeRestore.toTilesSet()) runCurrent() @@ -351,6 +349,49 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { assertThat(tiles).isEqualTo(currentTiles) } + @Test + fun noSettingsStored_noTilesReadFromSettings() = + testScope.runTest { + val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tiles by collectLastValue(underTest.tiles()) + + assertThat(tiles).isEqualTo(getDefaultTileSpecs()) + assertThat(tilesRead).isEqualTo(null) + } + + @Test + fun settingsStored_tilesReadFromSettings() = + testScope.runTest { + val storedTiles = "a,b" + storeTiles(storedTiles) + val tiles by collectLastValue(underTest.tiles()) + val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + + assertThat(tilesRead).isEqualTo(storedTiles.toTilesSet()) + } + + @Test + fun noSettingsStored_tilesChanged_tilesReadFromSettingsNotChanged() = + testScope.runTest { + val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + val tiles by collectLastValue(underTest.tiles()) + + underTest.addTile(TileSpec.create("a")) + assertThat(tilesRead).isEqualTo(null) + } + + @Test + fun settingsStored_tilesChanged_tilesReadFromSettingsNotChanged() = + testScope.runTest { + val storedTiles = "a,b" + storeTiles(storedTiles) + val tiles by collectLastValue(underTest.tiles()) + val tilesRead by collectLastValue(underTest.tilesReadFromSettings.consumeAsFlow()) + + underTest.addTile(TileSpec.create("c")) + assertThat(tilesRead).isEqualTo(storedTiles.toTilesSet()) + } + private fun getDefaultTileSpecs(): List<TileSpec> { return defaultTilesRepository.defaultTiles } @@ -370,6 +411,7 @@ class UserTileSpecRepositoryTest : SysuiTestCase() { private const val SETTING = Settings.Secure.QS_TILES private fun String.toTileSpecs() = TilesSettingConverter.toTilesList(this) + private fun String.toTilesSet() = TilesSettingConverter.toTilesSet(this) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt index f4bf53cafd19..325c6cafc465 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.panels.dagger +import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory @@ -23,6 +24,7 @@ import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositor import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositoryImpl import com.android.systemui.qs.panels.domain.interactor.EditTilesResetInteractor import com.android.systemui.qs.panels.domain.interactor.SizedTilesResetInteractor +import com.android.systemui.qs.panels.domain.startable.QSPanelsCoreStartable import com.android.systemui.qs.panels.shared.model.GridLayoutType import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType @@ -36,6 +38,8 @@ import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModelImpl import dagger.Binds import dagger.Module import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap import dagger.multibindings.IntoSet import javax.inject.Named @@ -57,6 +61,11 @@ interface PanelsModule { @Binds @Named("Default") fun bindDefaultGridLayout(impl: PaginatedGridLayout): GridLayout + @Binds + @IntoMap + @ClassKey(QSPanelsCoreStartable::class) + fun bindQSPanelsCoreStartable(impl: QSPanelsCoreStartable): CoreStartable + companion object { @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt index 19e4fd5b21b0..16dff7d11002 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt @@ -84,11 +84,33 @@ constructor( /** Sets for the current user the set of [TileSpec] to display as large tiles. */ fun setLargeTilesSpecs(specs: Set<TileSpec>) { - with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) { + setLargeTilesSpecsForUser(specs, userRepository.getSelectedUserInfo().id) + } + + private fun setLargeTilesSpecsForUser(specs: Set<TileSpec>, userId: Int) { + with(getSharedPrefs(userId)) { edit().putStringSet(LARGE_TILES_SPECS_KEY, specs.map { it.spec }.toSet()).apply() } } + /** + * Sets the initial tiles as large, if there is no set in SharedPrefs for the [userId]. This is + * to be used when upgrading to a build that supports large/small tiles. + * + * Even if largeTilesSpec is read Eagerly before we know if we are in an initial state, because + * we are not writing the default values to the SharedPreferences, the file will not contain the + * key and this call will succeed, as long as there hasn't been any calls to setLargeTilesSpecs + * for that user before. + */ + fun setInitialLargeTilesSpecs(specs: Set<TileSpec>, userId: Int) { + with(getSharedPrefs(userId)) { + if (!contains(LARGE_TILES_SPECS_KEY)) { + logger.i("Setting upgraded large tiles for user $userId: $specs") + setLargeTilesSpecsForUser(specs, userId) + } + } + } + private fun getSharedPrefs(userId: Int): SharedPreferences { return userFileManager.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, userId) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt index 23c79f576df5..482cd4014acf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt @@ -44,6 +44,7 @@ constructor( @PanelsLog private val logBuffer: LogBuffer, @Application private val applicationScope: CoroutineScope, ) { + val largeTilesSpecs = preferencesInteractor.largeTilesSpecs .onEach { logChange(it) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt index 22543b12b93c..86838b438bc6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt @@ -29,4 +29,8 @@ class QSPreferencesInteractor @Inject constructor(private val repo: QSPreference fun setLargeTilesSpecs(specs: Set<TileSpec>) { repo.setLargeTilesSpecs(specs) } + + fun setInitialLargeTilesSpecs(specs: Set<TileSpec>, user: Int) { + repo.setInitialLargeTilesSpecs(specs, user) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt new file mode 100644 index 000000000000..a8ac5c34d8f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/startable/QSPanelsCoreStartable.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2025 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.qs.panels.domain.startable + +import com.android.app.tracing.coroutines.launchTraced +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.qs.panels.domain.interactor.QSPreferencesInteractor +import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.receiveAsFlow + +class QSPanelsCoreStartable +@Inject +constructor( + private val tileSpecRepository: TileSpecRepository, + private val preferenceInteractor: QSPreferencesInteractor, + @Background private val backgroundApplicationScope: CoroutineScope, +) : CoreStartable { + override fun start() { + backgroundApplicationScope.launchTraced("QSPanelsCoreStartable.startingLargeTiles") { + tileSpecRepository.tilesReadFromSetting.receiveAsFlow().collect { (tiles, userId) -> + preferenceInteractor.setInitialLargeTilesSpecs(tiles, userId) + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt index 4e993786e343..6b7dd386bb46 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt @@ -19,7 +19,9 @@ package com.android.systemui.qs.pipeline.data.repository import android.annotation.UserIdInt import android.content.res.Resources import android.util.SparseArray +import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger @@ -27,6 +29,9 @@ import com.android.systemui.res.R import com.android.systemui.retail.data.repository.RetailModeRepository import com.android.systemui.shade.ShadeDisplayAware import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -73,6 +78,8 @@ interface TileSpecRepository { /** Reset the current set of tiles to the default list of tiles */ suspend fun resetToDefault(userId: Int) + val tilesReadFromSetting: ReceiveChannel<Pair<Set<TileSpec>, Int>> + companion object { /** Position to indicate the end of the list */ const val POSITION_AT_END = -1 @@ -94,6 +101,7 @@ constructor( private val logger: QSPipelineLogger, private val retailModeRepository: RetailModeRepository, private val userTileSpecRepositoryFactory: UserTileSpecRepository.Factory, + @Background private val applicationScope: CoroutineScope, ) : TileSpecRepository { private val retailModeTiles by lazy { @@ -104,12 +112,20 @@ constructor( .filter { it !is TileSpec.Invalid } } + private val _tilesReadFromSetting = Channel<Pair<Set<TileSpec>, Int>>(capacity = 5) + override val tilesReadFromSetting = _tilesReadFromSetting + private val userTileRepositories = SparseArray<UserTileSpecRepository>() override suspend fun tilesSpecs(userId: Int): Flow<List<TileSpec>> { if (userId !in userTileRepositories) { val userTileRepository = userTileSpecRepositoryFactory.create(userId) userTileRepositories.put(userId, userTileRepository) + applicationScope.launchTraced("TileSpecRepository.aggregateTilesPerUser") { + for (tilesFromSettings in userTileRepository.tilesReadFromSettings) { + _tilesReadFromSetting.send(tilesFromSettings to userId) + } + } } val realTiles = userTileRepositories.get(userId).tiles() diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt index 64da853484ff..7b56cd92a081 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepository.kt @@ -3,6 +3,7 @@ package com.android.systemui.qs.pipeline.data.repository import android.annotation.UserIdInt import android.database.ContentObserver import android.provider.Settings +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.common.coroutine.ConflatedCallbackFlow import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background @@ -15,6 +16,8 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -23,7 +26,6 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.scan import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext /** @@ -47,6 +49,9 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, ) { + private val _tilesReadFromSettings = Channel<Set<TileSpec>>(capacity = 2) + val tilesReadFromSettings: ReceiveChannel<Set<TileSpec>> = _tilesReadFromSettings + private val defaultTiles: List<TileSpec> get() = defaultTilesRepository.defaultTiles @@ -147,7 +152,11 @@ constructor( } private suspend fun loadTilesFromSettingsAndParse(userId: Int): List<TileSpec> { - return parseTileSpecs(loadTilesFromSettings(userId), userId) + val loadedTiles = loadTilesFromSettings(userId) + if (loadedTiles.isNotEmpty()) { + _tilesReadFromSettings.send(loadedTiles.toSet()) + } + return parseTileSpecs(loadedTiles, userId) } private suspend fun loadTilesFromSettings(userId: Int): List<TileSpec> { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt index 1c69eab9602e..5fc31f8b9e10 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeTileSpecRepository.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.pipeline.data.repository import com.android.systemui.qs.pipeline.data.model.RestoreData import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END import com.android.systemui.qs.pipeline.shared.TileSpec +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -77,4 +78,10 @@ class FakeTileSpecRepository( override suspend fun resetToDefault(userId: Int) { with(getFlow(userId)) { value = defaultTilesRepository.defaultTiles } } + + override val tilesReadFromSetting: Channel<Pair<Set<TileSpec>, Int>> = Channel(capacity = 10) + + suspend fun sendTilesReadFromSetting(tiles: Set<TileSpec>, userId: Int) { + tilesReadFromSetting.send(tiles to userId) + } } |