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

Commit 16bb6d31 authored by Olivier St-Onge's avatar Olivier St-Onge Committed by Android (Google) Code Review
Browse files

Merge "Move the large tile span logic to the columns viewmodel" into main

parents c364d9f7 9e207bc5
Loading
Loading
Loading
Loading
+0 −147
Original line number Diff line number Diff line
/*
 * 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.interactor

import android.content.res.Configuration
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class LargeTileSpanInteractorTest : SysuiTestCase() {
    private val kosmos =
        testKosmos().useUnconfinedTestDispatcher().apply {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_num_columns,
                4,
            )
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_tile_max_width,
                4,
            )
        }
    private val Kosmos.underTest by Kosmos.Fixture { largeTileSpanInteractor }

    @Test
    fun span_normalTiles_ignoreColumns() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.span)

            // Set extra large tiles to false
            val configuration = Configuration().apply { this.fontScale = 1f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Not using extra large tiles means that we stay to the default width of 2, regardless
            // of columns
            assertThat(latest).isEqualTo(2)

            setColumns(10)
            assertThat(latest).isEqualTo(2)
        }

    @Test
    fun span_extraLargeTiles_tracksColumns() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.span)

            // Set extra large tiles to true
            val configuration = Configuration().apply { this.fontScale = 2f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Using extra large tiles with a max width of 4 means that we change the width to the
            // same as the columns if equal or under 4, otherwise we divide it in half
            assertThat(latest).isEqualTo(4)

            setColumns(2)
            assertThat(latest).isEqualTo(2)

            setColumns(6)
            assertThat(latest).isEqualTo(3)

            setColumns(8)
            assertThat(latest).isEqualTo(4)
        }

    @Test
    fun span_extraLargeTiles_tracksMaxWidth() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.span)

            // Set extra large tiles to true
            val configuration = Configuration().apply { this.fontScale = 2f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Using extra large tiles with 4 columns means that we change the width to be 4, unless
            // we're using a max width lower than 4 in which case divide it in half
            assertThat(latest).isEqualTo(4)

            setMaxWidth(3)
            assertThat(latest).isEqualTo(2)

            setMaxWidth(6)
            assertThat(latest).isEqualTo(4)

            setMaxWidth(8)
            assertThat(latest).isEqualTo(4)
        }

    @Test
    fun span_tracksExtraLargeTiles() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.span)

            // Set extra large tiles to false
            val configuration = Configuration().apply { this.fontScale = 1f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            assertThat(latest).isEqualTo(2)

            // Set extra large tiles to true
            configuration.fontScale = 2f
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(latest).isEqualTo(4)
        }

    private fun setColumns(columns: Int) =
        setValueInConfig(columns, R.integer.quick_settings_infinite_grid_num_columns)

    private fun setMaxWidth(width: Int) =
        setValueInConfig(width, R.integer.quick_settings_infinite_grid_tile_max_width)

    private fun setValueInConfig(value: Int, id: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(id, value)
            fakeConfigurationRepository.onConfigurationChange()
        }
}
+212 −0
Original line number Diff line number Diff line
@@ -14,17 +14,24 @@
 * limitations under the License.
 */

package com.android.systemui.qs.panels.ui.compose
package com.android.systemui.qs.panels.ui.viewmodel

import android.content.res.Configuration
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment
import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -34,23 +41,27 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class InfiniteGridLayoutTest : SysuiTestCase() {
class InfiniteGridViewModelTest : SysuiTestCase() {
    private val kosmos =
        testKosmos().apply {
        testKosmos().useUnconfinedTestDispatcher().apply {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_num_columns,
                4,
            )
            defaultLargeTilesRepository =
                object : DefaultLargeTilesRepository {
                    override val defaultLargeTiles: Set<TileSpec> = setOf(TileSpec.create("large"))
                }
            usingMediaInComposeFragment = false
        }

    private val underTest = kosmos.infiniteGridLayout
    private val Kosmos.underTest by Kosmos.Fixture { infiniteGridLayout.viewModelFactory.create() }

    @Test
    fun correctPagination_underOnePage_sameOrder() =
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
@@ -62,7 +73,7 @@ class InfiniteGridLayoutTest : SysuiTestCase() {
                        smallTile(),
                    )

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)
                val pages = underTest.splitIntoPages(tiles, rows = rows)

                assertThat(pages).hasSize(1)
                assertThat(pages[0]).isEqualTo(tiles)
@@ -74,7 +85,6 @@ class InfiniteGridLayoutTest : SysuiTestCase() {
        with(kosmos) {
            testScope.runTest {
                val rows = 3
                val columns = 4

                val tiles =
                    listOf(
@@ -99,7 +109,7 @@ class InfiniteGridLayoutTest : SysuiTestCase() {
                // [L L] [S] [S]
                // [L L]

                val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)
                val pages = underTest.splitIntoPages(tiles, rows = rows)

                assertThat(pages).hasSize(2)
                assertThat(pages[0]).isEqualTo(tiles.take(8))
@@ -107,6 +117,93 @@ class InfiniteGridLayoutTest : SysuiTestCase() {
            }
        }

    @Test
    fun correctPagination_differentColumns_sameOrder() =
        with(kosmos) {
            testScope.runTest {
                underTest.activateIn(testScope)
                val rows = 3

                // Set columns to 2
                testCase.context.orCreateTestableResources.addOverride(
                    R.integer.quick_settings_infinite_grid_num_columns,
                    2,
                )
                fakeConfigurationRepository.onConfigurationChange()

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        smallTile(),
                        largeTile(),
                    )
                // --- Page 1 ---
                // [L L] [S] [S]
                // [L L] [L L]
                // [S] [S] [L L]
                // --- Page 2 ---
                // [L L] [S] [S]
                // [L L]

                val pages = underTest.splitIntoPages(tiles, rows = rows)

                assertThat(pages).hasSize(3)
                assertThat(pages[0]).isEqualTo(tiles.take(4))
                assertThat(pages[1]).isEqualTo(tiles.subList(4, 8))
                assertThat(pages[2]).isEqualTo(tiles.drop(8))
            }
        }

    @Test
    fun correctPagination_extraLargeTiles_sameOrder() =
        with(kosmos) {
            testScope.runTest {
                underTest.activateIn(testScope)
                val rows = 3

                // Enable extra large tiles
                val configuration = Configuration().apply { this.fontScale = 2f }
                context.orCreateTestableResources.overrideConfiguration(configuration)
                fakeConfigurationRepository.onConfigurationChange()

                val tiles =
                    listOf(
                        largeTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        largeTile(),
                        largeTile(),
                        smallTile(),
                        largeTile(),
                    )
                // --- Page 1 ---
                // [L L] [S] [S]
                // [L L] [L L]
                // [S] [S] [L L]
                // --- Page 2 ---
                // [L L] [S] [S]
                // [L L]

                val pages = underTest.splitIntoPages(tiles, rows = rows)

                assertThat(pages).hasSize(3)
                assertThat(pages[0]).isEqualTo(tiles.take(3))
                assertThat(pages[1]).isEqualTo(tiles.subList(3, 6))
                assertThat(pages[2]).isEqualTo(tiles.drop(6))
            }
        }

    companion object {
        fun largeTile() = MockTileViewModel(TileSpec.create("large"))

+6 −18
Original line number Diff line number Diff line
@@ -14,13 +14,12 @@
 * limitations under the License.
 */

package com.android.systemui.qs.panels.ui.compose
package com.android.systemui.qs.panels.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -29,24 +28,18 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class PaginatableGridLayoutTest : SysuiTestCase() {
class PaginatableViewModelTest : SysuiTestCase() {
    @Test
    fun correctRows_gapsAtEnd() {
        val columns = 6

        val sizedTiles =
            listOf(
                largeTile(),
                extraLargeTile(),
                largeTile(),
                smallTile(),
                largeTile(),
            )
            listOf(largeTile(), extraLargeTile(), largeTile(), smallTile(), largeTile())

        // [L L] [XL XL XL]
        // [L L] [S] [L L]

        val rows = PaginatableGridLayout.splitInRows(sizedTiles, columns)
        val rows = PaginatableViewModel.splitInRows(sizedTiles, columns)

        assertThat(rows).hasSize(2)
        assertThat(rows[0]).isEqualTo(sizedTiles.take(2))
@@ -57,16 +50,11 @@ class PaginatableGridLayoutTest : SysuiTestCase() {
    fun correctRows_fullLastRow_noEmptyRow() {
        val columns = 6

        val sizedTiles =
            listOf(
                largeTile(),
                extraLargeTile(),
                smallTile(),
            )
        val sizedTiles = listOf(largeTile(), extraLargeTile(), smallTile())

        // [L L] [XL XL XL] [S]

        val rows = PaginatableGridLayout.splitInRows(sizedTiles, columns)
        val rows = PaginatableViewModel.splitInRows(sizedTiles, columns)

        assertThat(rows).hasSize(1)
        assertThat(rows[0]).isEqualTo(sizedTiles)
+106 −0
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

package com.android.systemui.qs.panels.ui.viewmodel

import android.content.res.Configuration
import android.content.res.mainResources
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.configurationRepository
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.runTest
@@ -64,6 +66,10 @@ class QSColumnsViewModelTest : SysuiTestCase() {
                R.integer.quick_settings_split_shade_num_columns,
                SINGLE_SPLIT_SHADE_COLUMNS,
            )
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_tile_max_width,
                4,
            )
            qsColumnsRepository = QSColumnsRepository(mainResources, configurationRepository)
        }

@@ -184,6 +190,106 @@ class QSColumnsViewModelTest : SysuiTestCase() {
            assertThat(underTest.columns).isEqualTo(SINGLE_SPLIT_SHADE_COLUMNS / 2)
        }

    @Test
    fun largeSpan_normalTiles_ignoreColumns() =
        kosmos.runTest {
            val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS)
            underTest.activateIn(testScope)

            // Set extra large tiles to false
            val configuration = Configuration().apply { this.fontScale = 1f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Not using extra large tiles means that we stay to the default width of 2, regardless
            // of columns
            assertThat(underTest.largeSpan).isEqualTo(2)

            setColumns(10)
            assertThat(underTest.largeSpan).isEqualTo(2)
        }

    @Test
    fun largeSpan_extraLargeTiles_tracksColumns() =
        kosmos.runTest {
            val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS)
            underTest.activateIn(testScope)

            // Set extra large tiles to true
            val configuration = Configuration().apply { this.fontScale = 2f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Using extra large tiles with a max width of 4 means that we change the width to the
            // same as the columns if equal or under 4, otherwise we divide it in half
            assertThat(underTest.largeSpan).isEqualTo(4)

            setColumns(2)
            assertThat(underTest.largeSpan).isEqualTo(2)

            setColumns(6)
            assertThat(underTest.largeSpan).isEqualTo(3)

            setColumns(8)
            assertThat(underTest.largeSpan).isEqualTo(4)
        }

    @Test
    fun largeSpan_extraLargeTiles_tracksMaxWidth() =
        kosmos.runTest {
            val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS)
            underTest.activateIn(testScope)

            // Set extra large tiles to true
            val configuration = Configuration().apply { this.fontScale = 2f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            // Using extra large tiles with 4 columns means that we change the width to be 4, unless
            // we're using a max width lower than 4 in which case divide it in half
            assertThat(underTest.largeSpan).isEqualTo(4)

            setMaxWidth(3)
            assertThat(underTest.largeSpan).isEqualTo(2)

            setMaxWidth(6)
            assertThat(underTest.largeSpan).isEqualTo(4)

            setMaxWidth(8)
            assertThat(underTest.largeSpan).isEqualTo(4)
        }

    @Test
    fun largeSpan_tracksExtraLargeTiles() =
        kosmos.runTest {
            val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS)
            underTest.activateIn(testScope)

            // Set extra large tiles to false
            val configuration = Configuration().apply { this.fontScale = 1f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()

            assertThat(underTest.largeSpan).isEqualTo(2)

            // Set extra large tiles to true
            configuration.fontScale = 2f
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(underTest.largeSpan).isEqualTo(4)
        }

    private fun setColumns(columns: Int) =
        setValueInConfig(columns, R.integer.quick_settings_infinite_grid_num_columns)

    private fun setMaxWidth(width: Int) =
        setValueInConfig(width, R.integer.quick_settings_infinite_grid_tile_max_width)

    private fun setValueInConfig(value: Int, id: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(id, value)
            fakeConfigurationRepository.onConfigurationChange()
        }

    companion object {
        private const val SINGLE_SPLIT_SHADE_COLUMNS = 4
        private const val DUAL_SHADE_COLUMNS = 2
+0 −4
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import com.android.systemui.qs.pipeline.shared.metricSpec
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn

@@ -43,7 +42,6 @@ constructor(
    private val currentTilesInteractor: CurrentTilesInteractor,
    private val preferencesInteractor: QSPreferencesInteractor,
    private val uiEventLogger: UiEventLogger,
    largeTilesSpanInteractor: LargeTileSpanInteractor,
    @PanelsLog private val logBuffer: LogBuffer,
    @Background private val scope: CoroutineScope,
) {
@@ -53,8 +51,6 @@ constructor(
            .onEach { logChange(it) }
            .stateIn(scope, SharingStarted.Eagerly, repo.defaultLargeTiles)

    val largeTilesSpan: StateFlow<Int> = largeTilesSpanInteractor.span

    fun isIconTile(spec: TileSpec): Boolean = !largeTilesSpecs.value.contains(spec)

    /** Set the large tiles to be [specs] */
Loading