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

Commit a8d1d466 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Add RestrictedMenuItem for Spa

Similar to RestrictedSwitchPreference, could apply restrictions to
MenuItem.

Bug: 259492166
Test: Unit test
Test: Manually with Settings
Change-Id: I3af06f53e64888d6d24fc39fcb96e9bbed0b05ea
parent c9d48ffd
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spaprivileged.template.scaffold

import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl

@Composable
fun MoreOptionsScope.RestrictedMenuItem(
    text: String,
    restrictions: Restrictions,
    onClick: () -> Unit,
) {
    RestrictedMenuItemImpl(text, restrictions, onClick, ::RestrictionsProviderImpl)
}

@Composable
internal fun MoreOptionsScope.RestrictedMenuItemImpl(
    text: String,
    restrictions: Restrictions,
    onClick: () -> Unit,
    restrictionsProviderFactory: (Context, Restrictions) -> RestrictionsProvider,
) {
    val context = LocalContext.current
    val restrictionsProvider = remember(restrictions) {
        restrictionsProviderFactory(context, restrictions)
    }
    val restrictedMode = restrictionsProvider.restrictedModeState().value
    MenuItem(text = text, enabled = restrictedMode !is BaseUserRestricted) {
        when (restrictedMode) {
            is BlockedByAdmin -> restrictedMode.sendShowAdminSupportDetailsIntent()
            else -> onClick()
        }
    }
}
+4 −23
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settingslib.spaprivileged.template.preference

import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
@@ -28,14 +27,12 @@ import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
import com.android.settingslib.spaprivileged.tests.testutils.FakeBlockedByAdmin
import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
@@ -46,15 +43,7 @@ class RestrictedSwitchPreferenceTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    private val fakeBlockedByAdmin = object : BlockedByAdmin {
        var sendShowAdminSupportDetailsIntentIsCalled = false

        override fun getSummary(checked: Boolean?) = BLOCKED_BY_ADMIN_SUMMARY

        override fun sendShowAdminSupportDetailsIntent() {
            sendShowAdminSupportDetailsIntentIsCalled = true
        }
    }
    private val fakeBlockedByAdmin = FakeBlockedByAdmin()

    private val fakeRestrictionsProvider = FakeRestrictionsProvider()

@@ -136,7 +125,7 @@ class RestrictedSwitchPreferenceTest {
        setContent(restrictions)

        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsEnabled()
        composeTestRule.onNodeWithText(BLOCKED_BY_ADMIN_SUMMARY).assertIsDisplayed()
        composeTestRule.onNodeWithText(FakeBlockedByAdmin.SUMMARY).assertIsDisplayed()
        composeTestRule.onNode(isOn()).assertIsDisplayed()
    }

@@ -163,13 +152,5 @@ class RestrictedSwitchPreferenceTest {
        const val TITLE = "Title"
        const val USER_ID = 0
        const val RESTRICTION_KEY = "restriction_key"
        const val BLOCKED_BY_ADMIN_SUMMARY = "Blocked by admin"
    }
}

private class FakeRestrictionsProvider : RestrictionsProvider {
    var restrictedMode: RestrictedMode? = null

    @Composable
    override fun restrictedModeState() = stateOf(restrictedMode)
}
+151 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spaprivileged.template.scaffold

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.tests.testutils.FakeBlockedByAdmin
import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class RestrictedMenuItemTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    private val fakeBlockedByAdmin = FakeBlockedByAdmin()

    private val fakeRestrictionsProvider = FakeRestrictionsProvider()

    private var menuItemOnClickIsCalled = false

    @Test
    fun whenRestrictionsKeysIsEmpty_enabled() {
        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())

        setContent(restrictions)

        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
    }

    @Test
    fun whenRestrictionsKeysIsEmpty_clickable() {
        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())

        setContent(restrictions)
        composeTestRule.onRoot().performClick()

        assertThat(menuItemOnClickIsCalled).isTrue()
    }

    @Test
    fun whenNoRestricted_enabled() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = NoRestricted

        setContent(restrictions)

        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
    }

    @Test
    fun whenNoRestricted_clickable() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = NoRestricted

        setContent(restrictions)
        composeTestRule.onRoot().performClick()

        assertThat(menuItemOnClickIsCalled).isTrue()
    }

    @Test
    fun whenBaseUserRestricted_disabled() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted

        setContent(restrictions)

        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsNotEnabled()
    }

    @Test
    fun whenBaseUserRestricted_notClickable() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted

        setContent(restrictions)
        composeTestRule.onRoot().performClick()

        assertThat(menuItemOnClickIsCalled).isFalse()
    }

    @Test
    fun whenBlockedByAdmin_disabled() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin

        setContent(restrictions)

        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
    }

    @Test
    fun whenBlockedByAdmin_onClick_showAdminSupportDetails() {
        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin

        setContent(restrictions)
        composeTestRule.onRoot().performClick()

        assertThat(fakeBlockedByAdmin.sendShowAdminSupportDetailsIntentIsCalled).isTrue()
        assertThat(menuItemOnClickIsCalled).isFalse()
    }

    private fun setContent(restrictions: Restrictions) {
        val fakeMoreOptionsScope = object : MoreOptionsScope {
            override fun dismiss() {}
        }
        composeTestRule.setContent {
            fakeMoreOptionsScope.RestrictedMenuItemImpl(
                text = TEXT,
                restrictions = restrictions,
                onClick = { menuItemOnClickIsCalled = true },
                restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
            )
        }
    }

    private companion object {
        const val TEXT = "Text"
        const val USER_ID = 0
        const val RESTRICTION_KEY = "restriction_key"
    }
}
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spaprivileged.tests.testutils

import androidx.compose.runtime.Composable
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider

class FakeBlockedByAdmin : BlockedByAdmin {
    var sendShowAdminSupportDetailsIntentIsCalled = false

    override fun getSummary(checked: Boolean?) = SUMMARY

    override fun sendShowAdminSupportDetailsIntent() {
        sendShowAdminSupportDetailsIntentIsCalled = true
    }

    companion object {
        const val SUMMARY = "Blocked by admin"
    }
}

class FakeRestrictionsProvider : RestrictionsProvider {
    var restrictedMode: RestrictedMode? = null

    @Composable
    override fun restrictedModeState() = stateOf(restrictedMode)
}