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

Commit 22663d99 authored by Olivier St-Onge's avatar Olivier St-Onge
Browse files

Use the number of columns for extra large tiles, or half if past the threshold

Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Fixes: 416742299
Test: LargeTileSpanRepositoryTest.kt
Test: LargeTileSpanInteractorTest.kt
Change-Id: I0fcbb0f99d67f1c02a4b9c1c30d04be197dfe7a2
parent 921f2de4
Loading
Loading
Loading
Loading
+91 −0
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.data.repository

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)
class LargeTileSpanRepositoryTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val Kosmos.underTest by Kosmos.Fixture { largeTileSpanRepository }

    @Test
    fun useExtraLargeTiles_tracksConfig() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.useExtraLargeTiles)

            setFontScale(1f)
            assertThat(latest).isFalse()

            setFontScale(1.3f)
            assertThat(latest).isFalse()

            setFontScale(1.5f)
            assertThat(latest).isFalse()

            setFontScale(1.8f)
            assertThat(latest).isTrue()

            setFontScale(2f)
            assertThat(latest).isTrue()
        }

    @Test
    fun tileMaxWidth_tracksConfig() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.tileMaxWidth)

            setColumnsInConfig(1)
            assertThat(latest).isEqualTo(1)

            setColumnsInConfig(4)
            assertThat(latest).isEqualTo(4)

            setColumnsInConfig(8)
            assertThat(latest).isEqualTo(8)
        }

    private fun setFontScale(value: Float) {
        with(kosmos) {
            testCase.context.resources.configuration.fontScale = value
            fakeConfigurationRepository.onConfigurationChange()
        }
    }

    private fun setColumnsInConfig(columns: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_tile_max_width,
                columns,
            )
            fakeConfigurationRepository.onConfigurationChange()
        }
}
+135 −0
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 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)
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)
            setExtraLargeTiles(useExtraLargeTiles = false)

            // 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)
            setExtraLargeTiles(useExtraLargeTiles = true)

            // 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)
            setExtraLargeTiles(useExtraLargeTiles = true)

            // 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)

            setExtraLargeTiles(useExtraLargeTiles = false)
            assertThat(latest).isEqualTo(2)

            setExtraLargeTiles(useExtraLargeTiles = true)
            assertThat(latest).isEqualTo(4)
        }

    private fun setExtraLargeTiles(useExtraLargeTiles: Boolean) {
        with(kosmos) {
            val fontScale = if (useExtraLargeTiles) 2f else 1f
            testCase.context.resources.configuration.fontScale = fontScale
            fakeConfigurationRepository.onConfigurationChange()
        }
    }

    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()
        }
}
+0 −3
Original line number Diff line number Diff line
@@ -33,9 +33,6 @@
    <!-- The number of columns in the infinite grid QuickSettings -->
    <integer name="quick_settings_infinite_grid_num_columns">6</integer>

    <!-- The maximum width of large tiles in the infinite grid QuickSettings -->
    <integer name="quick_settings_infinite_grid_tile_max_width">3</integer>

    <integer name="power_menu_lite_max_columns">2</integer>
    <integer name="power_menu_lite_max_rows">3</integer>

+21 −16
Original line number Diff line number Diff line
@@ -19,40 +19,45 @@ package com.android.systemui.qs.panels.data.repository
import android.content.res.Resources
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn

@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class LargeTileSpanRepository
@Inject
constructor(
    @Application scope: CoroutineScope,
    @ShadeDisplayAware private val resources: Resources,
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
) {
    val span: StateFlow<Int> =
    val useExtraLargeTiles: Flow<Boolean> =
        configurationRepository.onConfigurationChange
            .emitOnStart()
            .mapLatest {
                if (resources.configuration.fontScale >= FONT_SCALE_THRESHOLD) {
                    resources.getInteger(R.integer.quick_settings_infinite_grid_tile_max_width)
                } else {
                    2
                }
            }
            .mapLatest { currentUseExtraLargeTiles }
            .distinctUntilChanged()
            .stateIn(scope, SharingStarted.WhileSubscribed(), 2)

    val tileMaxWidth: Flow<Int> =
        configurationRepository.onConfigurationChange
            .emitOnStart()
            .mapLatest { currentTileMaxWidth }
            .distinctUntilChanged()

    val defaultTileMaxWidth: Int = DEFAULT_LARGE_TILE_WIDTH

    val currentUseExtraLargeTiles: Boolean
        get() = resources.configuration.fontScale >= FONT_SCALE_THRESHOLD

    val currentTileMaxWidth: Int
        get() = resources.getInteger(R.integer.quick_settings_infinite_grid_tile_max_width)

    private companion object {
        const val FONT_SCALE_THRESHOLD = 2f
        const val FONT_SCALE_THRESHOLD = 1.8f
        const val DEFAULT_LARGE_TILE_WIDTH = 2
    }
}
+6 −3
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest

@SysUISingleton
@@ -35,9 +34,13 @@ constructor(
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
) {
    val splitShadeColumns: Flow<Int> =
        flowOf(resources.getInteger(R.integer.quick_settings_split_shade_num_columns))
        configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
            resources.getInteger(R.integer.quick_settings_split_shade_num_columns)
        }
    val dualShadeColumns: Flow<Int> =
        flowOf(resources.getInteger(R.integer.quick_settings_dual_shade_num_columns))
        configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
            resources.getInteger(R.integer.quick_settings_dual_shade_num_columns)
        }
    val columns: Flow<Int> =
        configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
            resources.getInteger(R.integer.quick_settings_infinite_grid_num_columns)
Loading