Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07075292 authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Prevent infinite appending default in retail mode

When in reatil mode, we restrict the tiles that are shown to a small
set. However, that set is the same size as the minimum number of tiles.
If any of those tiles cannot be created (for example, flashlight in
large devices), we end up with less tiles than the minimum, which will
trigger a `prependDefault`. However, as the CurrentTilesInteractor only
sees the retail tiles, this will keep happening and the tiles in
Settings will grow unbounded, crashing the device. We fix this at
a handful of points:

* When applying a change to the tiles, apply `distinct` so that only the
  first copy of each tile is saved.
* Prevent TileSpecRepository from applying prependDefault when in
  retailMode (same as other tile operations).
* When in retail mode, the min number of tiles in the
  CurrentTilesInteractor is reduced to 1.

Test: atest com.android.systemui.qs.pipeline
Fixes: 340450011
Flag: EXEMPT Bug Fix
Change-Id: I8771f0a8ae8b88e5d3600b35ee96901fc46cbc53
parent 2b3fd07b
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -203,6 +203,21 @@ class TileSpecSettingsRepositoryTest : SysuiTestCase() {
                .containsExactlyElementsIn(DEFAULT_TILES.toTileSpecs() + startingTiles)
        }

    @Test
    fun prependDefault_noChangesWhenInRetail() =
        testScope.runTest {
            val user = 0
            retailModeRepository.setRetailMode(true)
            val startingTiles = "a"
            storeTilesForUser(startingTiles, user)

            runCurrent()
            underTest.prependDefault(user)
            runCurrent()

            assertThat(loadTilesForUser(user)).isEqualTo(startingTiles)
        }

    private fun TestScope.storeTilesForUser(specs: String, forUser: Int) {
        secureSettings.putStringForUser(SETTING, specs, forUser)
        runCurrent()
+26 −0
Original line number Diff line number Diff line
@@ -327,6 +327,32 @@ class UserTileSpecRepositoryTest : SysuiTestCase() {
            assertThat(loadTiles()).isEqualTo(expected)
        }

    @Test
    fun setTilesWithRepeats_onlyDistinctTiles() =
        testScope.runTest {
            val tilesToSet = "a,b,c,a,d,b".toTileSpecs()
            val expected = "a,b,c,d"

            val tiles by collectLastValue(underTest.tiles())
            underTest.setTiles(tilesToSet)

            assertThat(tiles).isEqualTo(expected.toTileSpecs())
            assertThat(loadTiles()).isEqualTo(expected)
        }

    @Test
    fun prependDefaultTwice_doesntAddMoreTiles() =
        testScope.runTest {
            val tiles by collectLastValue(underTest.tiles())
            underTest.setTiles(listOf(TileSpec.create("a")))

            underTest.prependDefault()
            val currentTiles = tiles!!
            underTest.prependDefault()

            assertThat(tiles).isEqualTo(currentTiles)
        }

    private fun getDefaultTileSpecs(): List<TileSpec> {
        return defaultTilesRepository.defaultTiles
    }
+3 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import com.android.systemui.qs.tiles.di.NewQSTileFactory
import com.android.systemui.qs.toProto
import com.android.systemui.retail.data.repository.FakeRetailModeRepository
import com.android.systemui.settings.UserTracker
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.any
@@ -85,6 +86,7 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
    private val pipelineFlags = QSPipelineFlagsRepository()
    private val tileLifecycleManagerFactory = TLMFactory()
    private val minimumTilesRepository = MinimumTilesFixedRepository()
    private val retailModeRepository = FakeRetailModeRepository()

    @Mock private lateinit var customTileStatePersister: CustomTileStatePersister

@@ -118,6 +120,7 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
                installedTilesComponentRepository = installedTilesPackageRepository,
                userRepository = userRepository,
                minimumTilesRepository = minimumTilesRepository,
                retailModeRepository = retailModeRepository,
                customTileStatePersister = customTileStatePersister,
                tileFactory = tileFactory,
                newQSTileFactory = { newQSTileFactory },
+15 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import com.android.systemui.qs.pipeline.data.repository.MinimumTilesFixedReposit
import com.android.systemui.qs.pipeline.data.repository.fakeDefaultTilesRepository
import com.android.systemui.qs.pipeline.data.repository.fakeMinimumTilesRepository
import com.android.systemui.qs.pipeline.data.repository.fakeRestoreRepository
import com.android.systemui.qs.pipeline.data.repository.fakeRetailModeRepository
import com.android.systemui.qs.pipeline.data.repository.fakeTileSpecRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.qsTileFactory
import com.android.systemui.settings.fakeUserTracker
@@ -138,6 +140,19 @@ class NoLowNumberOfTilesTest : SysuiTestCase() {
            }
        }

    @Test
    fun inRetailMode_onlyOneTile_noPrependDefault() =
        with(kosmos) {
            testScope.runTest {
                fakeRetailModeRepository.setRetailMode(true)
                fakeTileSpecRepository.setTiles(0, listOf(goodTile))
                val tiles by collectLastValue(currentTilesInteractor.currentTiles)
                runCurrent()

                assertThat(tiles!!.map { it.spec }).isEqualTo(listOf(goodTile))
            }
        }

    private fun tileCreator(spec: String): QSTile? {
        return if (spec.contains("OEM")) {
            null // We don't know how to create OEM spec tiles
+3 −0
Original line number Diff line number Diff line
@@ -158,6 +158,9 @@ constructor(
    override suspend fun prependDefault(
        userId: Int,
    ) {
        if (retailModeRepository.inRetailMode) {
            return
        }
        userTileRepositories.get(userId)?.prependDefault()
    }

Loading