diff options
| author | 2024-07-25 12:14:38 -0400 | |
|---|---|---|
| committer | 2024-07-26 10:12:28 -0400 | |
| commit | c018d4b3d8e220e27a6d79eb063156a93b89f9f3 (patch) | |
| tree | 62be05abd66298cbd407c3f27c9f9a45ad5770fd | |
| parent | 8a2256314d3ddd7e91d99e714b547006cdf8f98b (diff) | |
Do not remove work tile from inside the tile.
AutoAddable will take care of removing it for the correct user, as it
gets its user from CurrentTilesInteractor.
Also, fix user switch in CurrentTilesInteractor. It was triggering more
often than it should.
Test: manual
Fixes: 352008994
Flag: EXEMPT bugfix
Change-Id: If1b66e06649566335ee904e3d40f11cc3c921064
6 files changed, 128 insertions, 107 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt index 6ad4b317b94c..314631823e96 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt @@ -675,6 +675,24 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() { assertThat(tiles!!.size).isEqualTo(3) } + @Test + fun changeInPackagesTiles_doesntTriggerUserChange_logged() = + testScope.runTest(USER_INFO_0) { + val specs = + listOf( + TileSpec.create("a"), + ) + tileSpecRepository.setTiles(USER_INFO_0.id, specs) + runCurrent() + // Settled on the same list of tiles. + assertThat(underTest.currentTilesSpecs).isEqualTo(specs) + + installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet()) + runCurrent() + + verify(logger, never()).logTileUserChanged(TileSpec.create("a"), 0) + } + private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) { this.state = state this.label = label diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt index 97b5e87d7167..02379e6efecc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt @@ -46,7 +46,7 @@ import com.android.systemui.qs.toProto import com.android.systemui.retail.data.repository.RetailModeRepository import com.android.systemui.settings.UserTracker import com.android.systemui.user.data.repository.UserRepository -import com.android.systemui.util.kotlin.pairwise +import com.android.systemui.util.kotlin.pairwiseBy import dagger.Lazy import java.io.PrintWriter import javax.inject.Inject @@ -63,7 +63,6 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -169,17 +168,19 @@ constructor( private val userAndTiles = currentUser .flatMapLatest { userId -> - tileSpecRepository.tilesSpecs(userId).map { UserAndTiles(userId, it) } + val currentTiles = tileSpecRepository.tilesSpecs(userId) + val installedComponents = + installedTilesComponentRepository.getInstalledTilesComponents(userId) + currentTiles.combine(installedComponents) { tiles, components -> + UserTilesAndComponents(userId, tiles, components) + } } .distinctUntilChanged() - .pairwise(UserAndTiles(-1, emptyList())) + .pairwiseBy(UserTilesAndComponents(-1, emptyList(), emptySet())) { prev, new -> + DataWithUserChange(data = new, userChange = prev.userId != new.userId) + } .flowOn(backgroundDispatcher) - private val installedPackagesWithTiles = - currentUser.flatMapLatest { - installedTilesComponentRepository.getInstalledTilesComponents(it) - } - private val minTiles: Int get() = if (retailModeRepository.inRetailMode) { @@ -194,7 +195,6 @@ constructor( } } - @OptIn(ExperimentalCoroutinesApi::class) private fun startTileCollection() { scope.launch { launch { @@ -205,95 +205,82 @@ constructor( } launch(backgroundDispatcher) { - userAndTiles - .combine(installedPackagesWithTiles) { usersAndTiles, packages -> - Data( - usersAndTiles.previousValue, - usersAndTiles.newValue, - packages, - ) - } - .collectLatest { - val newTileList = it.newData.tiles - val userChanged = it.oldData.userId != it.newData.userId - val newUser = it.newData.userId - val components = it.installedComponents - - // Destroy all tiles that are not in the new set - specsToTiles - .filter { - it.key !in newTileList && it.value is TileOrNotInstalled.Tile - } - .forEach { entry -> - logger.logTileDestroyed( - entry.key, - if (userChanged) { - QSPipelineLogger.TileDestroyedReason - .TILE_NOT_PRESENT_IN_NEW_USER - } else { - QSPipelineLogger.TileDestroyedReason.TILE_REMOVED - } - ) - (entry.value as TileOrNotInstalled.Tile).tile.destroy() - } - // MutableMap will keep the insertion order - val newTileMap = mutableMapOf<TileSpec, TileOrNotInstalled>() - - newTileList.forEach { tileSpec -> - if (tileSpec !in newTileMap) { - if ( - tileSpec is TileSpec.CustomTileSpec && - tileSpec.componentName !in components - ) { - newTileMap[tileSpec] = TileOrNotInstalled.NotInstalled + userAndTiles.collectLatest { + val newUser = it.userId + val newTileList = it.tiles + val components = it.installedComponents + val userChanged = it.userChange + + // Destroy all tiles that are not in the new set + specsToTiles + .filter { it.key !in newTileList && it.value is TileOrNotInstalled.Tile } + .forEach { entry -> + logger.logTileDestroyed( + entry.key, + if (userChanged) { + QSPipelineLogger.TileDestroyedReason + .TILE_NOT_PRESENT_IN_NEW_USER } else { - // Create tile here will never try to create a CustomTile that - // is not installed - val newTile = - if (tileSpec in specsToTiles) { - processExistingTile( - tileSpec, - specsToTiles.getValue(tileSpec), - userChanged, - newUser - ) - ?: createTile(tileSpec) - } else { - createTile(tileSpec) - } - if (newTile != null) { - newTileMap[tileSpec] = TileOrNotInstalled.Tile(newTile) + QSPipelineLogger.TileDestroyedReason.TILE_REMOVED + } + ) + (entry.value as TileOrNotInstalled.Tile).tile.destroy() + } + // MutableMap will keep the insertion order + val newTileMap = mutableMapOf<TileSpec, TileOrNotInstalled>() + + newTileList.forEach { tileSpec -> + if (tileSpec !in newTileMap) { + if ( + tileSpec is TileSpec.CustomTileSpec && + tileSpec.componentName !in components + ) { + newTileMap[tileSpec] = TileOrNotInstalled.NotInstalled + } else { + // Create tile here will never try to create a CustomTile that + // is not installed + val newTile = + if (tileSpec in specsToTiles) { + processExistingTile( + tileSpec, + specsToTiles.getValue(tileSpec), + userChanged, + newUser + ) ?: createTile(tileSpec) + } else { + createTile(tileSpec) } + if (newTile != null) { + newTileMap[tileSpec] = TileOrNotInstalled.Tile(newTile) } } } + } - val resolvedSpecs = newTileMap.keys.toList() - specsToTiles.clear() - specsToTiles.putAll(newTileMap) - val newResolvedTiles = - newTileMap - .filter { it.value is TileOrNotInstalled.Tile } - .map { - TileModel(it.key, (it.value as TileOrNotInstalled.Tile).tile) - } - - _currentSpecsAndTiles.value = newResolvedTiles - logger.logTilesNotInstalled( - newTileMap.filter { it.value is TileOrNotInstalled.NotInstalled }.keys, - newUser - ) - if (newResolvedTiles.size < minTiles) { - // We ended up with not enough tiles (some may be not installed). - // Prepend the default set of tiles - launch { tileSpecRepository.prependDefault(currentUser.value) } - } else if (resolvedSpecs != newTileList) { - // There were some tiles that couldn't be created. Change the value in - // the - // repository - launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) } - } + val resolvedSpecs = newTileMap.keys.toList() + specsToTiles.clear() + specsToTiles.putAll(newTileMap) + val newResolvedTiles = + newTileMap + .filter { it.value is TileOrNotInstalled.Tile } + .map { TileModel(it.key, (it.value as TileOrNotInstalled.Tile).tile) } + + _currentSpecsAndTiles.value = newResolvedTiles + logger.logTilesNotInstalled( + newTileMap.filter { it.value is TileOrNotInstalled.NotInstalled }.keys, + newUser + ) + if (newResolvedTiles.size < minTiles) { + // We ended up with not enough tiles (some may be not installed). + // Prepend the default set of tiles + launch { tileSpecRepository.prependDefault(currentUser.value) } + } else if (resolvedSpecs != newTileList) { + // There were some tiles that couldn't be created. Change the value in + // the + // repository + launch { tileSpecRepository.setTiles(currentUser.value, resolvedSpecs) } } + } } } } @@ -362,8 +349,7 @@ constructor( newQSTileFactory.get().createTile(spec.spec) } else { null - } - ?: tileFactory.createTile(spec.spec) + } ?: tileFactory.createTile(spec.spec) } if (tile == null) { logger.logTileNotFoundInFactory(spec) @@ -436,15 +422,25 @@ constructor( @JvmInline value class Tile(val tile: QSTile) : TileOrNotInstalled } +} - private data class UserAndTiles( - val userId: Int, - val tiles: List<TileSpec>, - ) - - private data class Data( - val oldData: UserAndTiles, - val newData: UserAndTiles, - val installedComponents: Set<ComponentName>, +private data class UserTilesAndComponents( + val userId: Int, + val tiles: List<TileSpec>, + val installedComponents: Set<ComponentName> +) + +private data class DataWithUserChange( + val userId: Int, + val tiles: List<TileSpec>, + val installedComponents: Set<ComponentName>, + val userChange: Boolean, +) + +private fun DataWithUserChange(data: UserTilesAndComponents, userChange: Boolean) = + DataWithUserChange( + data.userId, + data.tiles, + data.installedComponents, + userChange, ) -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index d9546ec6ac51..1750347fd2ae 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -106,7 +106,8 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements @Override @MainThread public void onManagedProfileRemoved() { - mHost.removeTile(getTileSpec()); + // No OP as this may race with the user change in CurrentTilesInteractor. + // If the tile needs to be removed, AutoAdd (or AutoTileManager) will take care of that. } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt index e9e9d8b0bbfc..cdcefdb50b0f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt @@ -22,12 +22,15 @@ import androidx.annotation.StringRes import com.android.internal.logging.InstanceId import com.android.systemui.qs.pipeline.shared.TileSpec -data class QSTileConfig( +data class QSTileConfig +@JvmOverloads +constructor( val tileSpec: TileSpec, val uiConfig: QSTileUIConfig, val instanceId: InstanceId, val metricsSpec: String = tileSpec.spec, val policy: QSTilePolicy = QSTilePolicy.NoRestrictions, + val autoRemoveOnUnavailable: Boolean = true, ) /** @@ -38,6 +41,7 @@ sealed interface QSTileUIConfig { val iconRes: Int @DrawableRes get + val labelRes: Int @StringRes get @@ -48,6 +52,7 @@ sealed interface QSTileUIConfig { data object Empty : QSTileUIConfig { override val iconRes: Int get() = Resources.ID_NULL + override val labelRes: Int get() = Resources.ID_NULL } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt index ba0a8d694a14..ba7994510063 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -72,7 +72,7 @@ constructor( applicationScope.launch { launch { qsTileViewModel.isAvailable.collectIndexed { index, isAvailable -> - if (!isAvailable) { + if (!isAvailable && qsTileViewModel.config.autoRemoveOnUnavailable) { qsHost.removeTile(tileSpec) } // qsTileViewModel.isAvailable flow often starts with isAvailable == true. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt index cf9a78f1c11c..fb915befb08c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt @@ -283,6 +283,7 @@ interface PolicyModule { labelRes = R.string.quick_settings_work_mode_label, ), instanceId = uiEventLogger.getNewInstanceId(), + autoRemoveOnUnavailable = false, ) /** Inject work mode into tileViewModelMap in QSModule */ |