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

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

Merge "Allow multiple user restrictions for tile policy" into main

parents 5f4f5e9a 73f87434
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ class QSTileLoggerTest : SysuiTestCase() {
        underTest.logUserActionRejectedByPolicy(
            QSTileUserAction.Click(null),
            TileSpec.create("test_spec"),
            "test_restriction",
        )

        assertThat(logBuffer.getStringBuffer()).contains("tile click: rejected by policy")
+3 −1
Original line number Diff line number Diff line
@@ -60,7 +60,9 @@ class QSTileViewModelTest : SysuiTestCase() {
    @Mock private lateinit var qsTileAnalytics: QSTileAnalytics

    private val tileConfig =
        QSTileConfigTestBuilder.build { policy = QSTilePolicy.Restricted("test_restriction") }
        QSTileConfigTestBuilder.build {
            policy = QSTilePolicy.Restricted(listOf("test_restriction"))
        }

    private val userRepository = FakeUserRepository()
    private val tileDataInteractor = FakeQSTileDataInteractor<String>()
+86 −10
Original line number Diff line number Diff line
@@ -16,18 +16,17 @@

package com.android.systemui.qs.tiles.viewmodel

import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.android.settingslib.RestrictedLockUtils
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor.Companion.DISABLED_RESTRICTION
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor.Companion.ENABLED_RESTRICTION
import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.FakeQSTileUserActionInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
@@ -54,7 +53,6 @@ import org.mockito.MockitoAnnotations

/** Tests all possible [QSTileUserAction]s. If you need */
@MediumTest
@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class QSTileViewModelUserInputTest : SysuiTestCase() {
@@ -65,8 +63,10 @@ class QSTileViewModelUserInputTest : SysuiTestCase() {
    // TODO(b/299909989): this should be parametrised. b/299096521 blocks this.
    private val userAction: QSTileUserAction = QSTileUserAction.Click(null)

    private val tileConfig =
        QSTileConfigTestBuilder.build { policy = QSTilePolicy.Restricted("test_restriction") }
    private var tileConfig =
        QSTileConfigTestBuilder.build {
            policy = QSTilePolicy.Restricted(listOf(ENABLED_RESTRICTION))
        }

    private val userRepository = FakeUserRepository()
    private val tileDataInteractor = FakeQSTileDataInteractor<String>()
@@ -112,11 +112,42 @@ class QSTileViewModelUserInputTest : SysuiTestCase() {
    @Test
    fun disabledByPolicyUserInputIsSkipped() =
        testScope.runTest {
            tileConfig =
                QSTileConfigTestBuilder.build {
                    policy = QSTilePolicy.Restricted(listOf(DISABLED_RESTRICTION))
                }
            underTest = createViewModel(testScope)
            underTest.state.launchIn(backgroundScope)
            disabledByPolicyInteractor.policyResult =
                DisabledByPolicyInteractor.PolicyResult.TileDisabled(
                    RestrictedLockUtils.EnforcedAdmin()

            runCurrent()

            underTest.onActionPerformed(userAction)
            runCurrent()

            assertThat(tileDataInteractor.triggers.last())
                .isNotInstanceOf(DataUpdateTrigger.UserInput::class.java)
            verify(qsTileLogger)
                .logUserActionRejectedByPolicy(
                    eq(userAction),
                    eq(tileConfig.tileSpec),
                    eq(DISABLED_RESTRICTION)
                )
            verify(qsTileAnalytics, never()).trackUserAction(any(), any())
        }

    @Test
    fun disabledByPolicySecondRestriction_userInputIsSkipped() =
        testScope.runTest {
            tileConfig =
                QSTileConfigTestBuilder.build {
                    policy =
                        QSTilePolicy.Restricted(listOf(ENABLED_RESTRICTION, DISABLED_RESTRICTION))
                }

            underTest = createViewModel(testScope)

            underTest.state.launchIn(backgroundScope)

            runCurrent()

            underTest.onActionPerformed(userAction)
@@ -125,7 +156,52 @@ class QSTileViewModelUserInputTest : SysuiTestCase() {
            assertThat(tileDataInteractor.triggers.last())
                .isNotInstanceOf(DataUpdateTrigger.UserInput::class.java)
            verify(qsTileLogger)
                .logUserActionRejectedByPolicy(eq(userAction), eq(tileConfig.tileSpec))
                .logUserActionRejectedByPolicy(
                    eq(userAction),
                    eq(tileConfig.tileSpec),
                    eq(DISABLED_RESTRICTION)
                )
            verify(qsTileAnalytics, never()).trackUserAction(any(), any())
        }

    /** This tests that the policies are applied sequentially */
    @Test
    fun disabledByPolicySecondRestriction_onlyFirstIsTriggered() =
        testScope.runTest {
            tileConfig =
                QSTileConfigTestBuilder.build {
                    policy =
                        QSTilePolicy.Restricted(
                            listOf(
                                DISABLED_RESTRICTION,
                                FakeDisabledByPolicyInteractor.DISABLED_RESTRICTION_2
                            )
                        )
                }

            underTest = createViewModel(testScope)

            underTest.state.launchIn(backgroundScope)

            runCurrent()

            underTest.onActionPerformed(userAction)
            runCurrent()

            assertThat(tileDataInteractor.triggers.last())
                .isNotInstanceOf(DataUpdateTrigger.UserInput::class.java)
            verify(qsTileLogger)
                .logUserActionRejectedByPolicy(
                    eq(userAction),
                    eq(tileConfig.tileSpec),
                    eq(DISABLED_RESTRICTION)
                )
            verify(qsTileLogger, never())
                .logUserActionRejectedByPolicy(
                    eq(userAction),
                    eq(tileConfig.tileSpec),
                    eq(FakeDisabledByPolicyInteractor.DISABLED_RESTRICTION_2)
                )
            verify(qsTileAnalytics, never()).trackUserAction(any(), any())
        }

+2 −1
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ constructor(
    fun logUserActionRejectedByPolicy(
        userAction: QSTileUserAction,
        tileSpec: TileSpec,
        restriction: String,
    ) {
        tileSpec
            .getLogBuffer()
@@ -95,7 +96,7 @@ constructor(
                tileSpec.getLogTag(),
                LogLevel.DEBUG,
                { str1 = userAction.toLogString() },
                { "tile $str1: rejected by policy" }
                { "tile $str1: rejected by policy, restriction: $restriction" }
            )
    }

+11 −6
Original line number Diff line number Diff line
@@ -178,7 +178,8 @@ class QSTileViewModelImpl<DATA_TYPE>(
    /**
     * Creates a user input flow which:
     * - filters false inputs with [falsingManager]
     * - takes care of a tile being disable by policy using [disabledByPolicyInteractor]
     * - takes care of a tile being disable by policy using [disabledByPolicyInteractor]. The
     *   restrictions will be checked sequentially and the first one to block will be considered.
     * - notifies [userActionInteractor] about the action
     * - logs it accordingly using [qsTileLogger] and [qsTileAnalytics]
     *
@@ -201,18 +202,22 @@ class QSTileViewModelImpl<DATA_TYPE>(
            .onEach { userActionInteractor().handleInput(it.input) }
            .flowOn(backgroundDispatcher)

    /**
     * The restrictions will be checked sequentially and the first one to block will be considered.
     */
    private fun Flow<QSTileUserAction>.filterByPolicy(user: UserHandle): Flow<QSTileUserAction> =
        config.policy.let { policy ->
            when (policy) {
                is QSTilePolicy.NoRestrictions -> this@filterByPolicy
                is QSTilePolicy.Restricted ->
                    filter { action ->
                        val result =
                            disabledByPolicyInteractor.isDisabled(user, policy.userRestriction)
                        !disabledByPolicyInteractor.handlePolicyResult(result).also { isDisabled ->
                            if (isDisabled) {
                                qsTileLogger.logUserActionRejectedByPolicy(action, spec)
                        policy.userRestrictions.none {
                            val result = disabledByPolicyInteractor.isDisabled(user, it)
                            val handleResult = disabledByPolicyInteractor.handlePolicyResult(result)
                            if (handleResult) {
                                qsTileLogger.logUserActionRejectedByPolicy(action, spec, it)
                            }
                            handleResult
                        }
                    }
            }
Loading