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

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

Merge "Reapply "Use the number of columns for extra large tiles, or half if...

Merge "Reapply "Use the number of columns for extra large tiles, or half if past the threshold"" into main
parents f1944fbb 4f117d04
Loading
Loading
Loading
Loading
+91 −0
Original line number Original line 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 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)
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)

            val configuration = Configuration().apply { this.fontScale = 1f }
            context.orCreateTestableResources.overrideConfiguration(configuration)
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(latest).isFalse()

            configuration.fontScale = 1.3f
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(latest).isFalse()

            configuration.fontScale = 1.5f
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(latest).isFalse()

            configuration.fontScale = 1.8f
            fakeConfigurationRepository.onConfigurationChange()
            assertThat(latest).isTrue()

            configuration.fontScale = 2f
            fakeConfigurationRepository.onConfigurationChange()
            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 setColumnsInConfig(columns: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_settings_infinite_grid_tile_max_width,
                columns,
            )
            fakeConfigurationRepository.onConfigurationChange()
        }
}
+146 −0
Original line number Original line 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)
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()
        }
}
+0 −3
Original line number Original line Diff line number Diff line
@@ -33,9 +33,6 @@
    <!-- The number of columns in the infinite grid QuickSettings -->
    <!-- The number of columns in the infinite grid QuickSettings -->
    <integer name="quick_settings_infinite_grid_num_columns">6</integer>
    <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_columns">2</integer>
    <integer name="power_menu_lite_max_rows">3</integer>
    <integer name="power_menu_lite_max_rows">3</integer>


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


@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
@SysUISingleton
class LargeTileSpanRepository
class LargeTileSpanRepository
@Inject
@Inject
constructor(
constructor(
    @Application scope: CoroutineScope,
    @ShadeDisplayAware private val resources: Resources,
    @ShadeDisplayAware private val resources: Resources,
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
) {
) {
    val span: StateFlow<Int> =
    val useExtraLargeTiles: Flow<Boolean> =
        configurationRepository.onConfigurationChange
        configurationRepository.onConfigurationChange
            .emitOnStart()
            .emitOnStart()
            .mapLatest {
            .mapLatest { currentUseExtraLargeTiles }
                if (resources.configuration.fontScale >= FONT_SCALE_THRESHOLD) {
                    resources.getInteger(R.integer.quick_settings_infinite_grid_tile_max_width)
                } else {
                    2
                }
            }
            .distinctUntilChanged()
            .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 {
    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 Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.kotlin.emitOnStart
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapLatest


@SysUISingleton
@SysUISingleton
@@ -35,9 +34,13 @@ constructor(
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
    @ShadeDisplayAware configurationRepository: ConfigurationRepository,
) {
) {
    val splitShadeColumns: Flow<Int> =
    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> =
    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> =
    val columns: Flow<Int> =
        configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
        configurationRepository.onConfigurationChange.emitOnStart().mapLatest {
            resources.getInteger(R.integer.quick_settings_infinite_grid_num_columns)
            resources.getInteger(R.integer.quick_settings_infinite_grid_num_columns)
Loading