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

Commit 6599936f authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use allow list for quick settings tiles for headless system user" into main

parents a6b6863e 33e01d59
Loading
Loading
Loading
Loading
+84 −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.pipeline.data.repository

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
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
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class HsuTilesRepositoryTest : SysuiTestCase() {

    private val kosmos = testKosmos()

    @Test
    fun isTileAllowed_withEmptyAllowList_allowAllTiles() =
        with(kosmos) {
            testScope.runTest {
                overrideAllowListResource(emptyArray())
                val underTest = HsuTilesRepository(testCase.context.resources)

                val result = underTest.isTileAllowed(TileSpec.create("a"))

                assertThat(result).isTrue()
            }
        }

    @Test
    fun isTileAllowed_withAllowList_returnTrueForAllowedTile() =
        with(kosmos) {
            testScope.runTest {
                overrideAllowListResource(arrayOf("a", "b"))
                val underTest = HsuTilesRepository(testCase.context.resources)

                val result = underTest.isTileAllowed(TileSpec.create("a"))

                assertThat(result).isTrue()
            }
        }

    @Test
    fun isTileAllowed_withAllowList_returnFalseForNotAllowedTile() =
        with(kosmos) {
            testScope.runTest {
                overrideAllowListResource(arrayOf("a", "b"))
                val underTest = HsuTilesRepository(testCase.context.resources)

                val result = underTest.isTileAllowed(TileSpec.create("c"))

                assertThat(result).isFalse()
            }
        }

    private fun overrideAllowListResource(allowList: Array<String>) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(
                R.array.hsu_allow_list_qs_tiles,
                allowList,
            )
        }
}
+57 −0
Original line number Diff line number Diff line
@@ -26,12 +26,14 @@ import android.service.quicksettings.Tile
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags
import com.android.systemui.Flags.FLAG_HSU_QS_CHANGES
import com.android.systemui.Flags.FLAG_QS_NEW_TILES
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.nano.SystemUIProtoDump
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTile.BooleanState
@@ -55,10 +57,12 @@ import com.android.systemui.qs.pipeline.shared.logging.qsLogger
import com.android.systemui.qs.qsTileFactory
import com.android.systemui.qs.tiles.base.ui.model.newQSTileFactory
import com.android.systemui.qs.toProto
import com.android.systemui.res.R
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.user.domain.interactor.fakeHeadlessSystemUserMode
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
@@ -811,6 +815,52 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
            }
        }

    @EnableFlags(FLAG_HSU_QS_CHANGES)
    @Test
    fun createAllowedTilesForHeadlessSystemUser() =
        with(kosmos) {
            testScope.runTest(USER_INFO_0) {
                val expectedTile = TileSpec.create("b")
                fakeHeadlessSystemUserMode.setIsHeadlessSystemUser(true)
                val allowList = arrayOf("b")
                overrideAllowListResource(allowList)
                val tiles by collectLastValue(underTest.currentTiles)
                val specs = listOf(TileSpec.create("a"), TileSpec.create("b"), TileSpec.create("d"))
                tileSpecRepository.setTiles(USER_INFO_0.id, specs)

                assertThat(tiles).hasSize(1)
                assertThat(tiles!![0].spec).isEqualTo(expectedTile)
            }
        }

    @EnableFlags(FLAG_HSU_QS_CHANGES)
    @Test
    fun userChangeToHeadlessSystemUser_notAllowedTileDestroyed() =
        with(kosmos) {
            testScope.runTest(USER_INFO_1) {
                val tiles by collectLastValue(underTest.currentTiles)
                val notAllowedTileForHsum = TileSpec.create("b")
                val specs1 = listOf(notAllowedTileForHsum)
                fakeHeadlessSystemUserMode.setIsHeadlessSystemUser(false)
                tileSpecRepository.setTiles(USER_INFO_1.id, specs1)
                val originalTileB = tiles!![0].tile

                val allowList = arrayOf("a")
                fakeHeadlessSystemUserMode.setIsHeadlessSystemUser(true)
                overrideAllowListResource(allowList)
                val expectedTile = TileSpec.create("a")
                val specs0 = listOf(expectedTile)
                tileSpecRepository.setTiles(USER_INFO_0.id, specs0)

                switchUser(USER_INFO_0)
                runCurrent()

                assertThat(originalTileB.isDestroyed).isTrue()
                assertThat(tiles).hasSize(1)
                assertThat(tiles!![0].spec).isEqualTo(expectedTile)
            }
        }

    private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
        this.state = state
        this.label = label
@@ -848,6 +898,13 @@ class CurrentTilesInteractorImplTest : SysuiTestCase() {
        }
    }

    private fun Kosmos.overrideAllowListResource(allowList: Array<String>) {
        testCase.context.orCreateTestableResources.addOverride(
            R.array.hsu_allow_list_qs_tiles,
            allowList,
        )
    }

    private fun TestScope.runTest(user: UserInfo, body: suspend TestScope.() -> Unit) {
        return kosmos.runTest {
            switchUser(user)
+9 −0
Original line number Diff line number Diff line
@@ -1178,6 +1178,15 @@
    <!-- Indicates post recording flow to use flat bottom bar to save vertical space -->
    <bool name="screen_record_post_recording_flat_bottom_bar">false</bool>

    <!-- List of allowed tiles for headless system user's quick settings.

         Some example values are 'alarm', 'internet', 'bt' (bluetooth),
         as defined by QSTile.getTileSpec().
    -->
    <string-array name="hsu_allow_list_qs_tiles" translatable="false">
        <!-- default empty and all tiles will be allowed -->
    </string-array>

    <!-- Indicates whether the blurred wallpaper is supported -->
    <bool name="config_supportBlurredWallpaper">true</bool>
</resources>
+40 −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.pipeline.data.model

import com.android.systemui.qs.pipeline.shared.TileSpec

/** Interface to represent which tiles are allowed. */
sealed interface AllowedTiles {

    /** Returns true if the given [spec] is allowed. */
    fun isTileAllowed(spec: TileSpec): Boolean

    /** Implementation of [AllowedTiles] that allows all tiles. */
    data object AllTiles : AllowedTiles {
        override fun isTileAllowed(spec: TileSpec): Boolean {
            return true
        }
    }

    /** Implementation of [AllowedTiles] that allows only specific tiles. */
    class SpecificTiles(private val tiles: List<TileSpec>) : AllowedTiles {
        override fun isTileAllowed(spec: TileSpec): Boolean {
            return spec in tiles
        }
    }
}
+46 −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.pipeline.data.repository

import android.content.res.Resources
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.pipeline.data.model.AllowedTiles
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeDisplayAware
import javax.inject.Inject

/** Repository for keeping track of the set of allowed tiles for the headless system user (hsu). */
@SysUISingleton
class HsuTilesRepository @Inject constructor(@ShadeDisplayAware private val resources: Resources) {

    /** Set of allowed tiles for the headless system user. */
    private val allowedTiles: AllowedTiles

    init {
        var allowList = resources.getStringArray(R.array.hsu_allow_list_qs_tiles)
        allowedTiles =
            if (allowList.size != 0)
                AllowedTiles.SpecificTiles(allowList.map { spec -> TileSpec.create(spec) })
            else AllowedTiles.AllTiles
    }

    /** Returns true if the given [spec] is allowed. */
    fun isTileAllowed(spec: TileSpec): Boolean {
        return allowedTiles.isTileAllowed(spec)
    }
}
Loading