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

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

Upgrade path for small/large tiles

When upgrading from a build that doesn't support dual size tiles to one
that does, we will force the current tiles for the user to be large
(once).

This is done by the following:
* If there is a list of tiles read from Settings AND
* The shared preference for large tiles is empty,

THEN we set the tiles read for that user to be large.

After that, if the user changes the tiles size or sets them to default, that
will be respected.

Test: atest com.android.systemui.qs
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Bug: 392615513
Change-Id: I3c024dc3c3f882a8a186c660d9094e6d07454c3f
parent 3a3c73d6
Loading
Loading
Loading
Loading
+109 −9
Original line number Diff line number Diff line
@@ -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)
+37 −0
Original line number Diff line number Diff line
@@ -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()
+47 −5
Original line number Diff line number Diff line
@@ -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)
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -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
+23 −1
Original line number Diff line number Diff line
@@ -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)
    }
Loading