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

Commit 38324149 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Create RestrictedPreference" into main

parents c130813d 0aa5fc83
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.os.UserHandle
import android.os.UserManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
@@ -32,15 +34,15 @@ import kotlinx.coroutines.flow.flowOn
import com.android.settingslib.widget.restricted.R

data class Restrictions(
    val userId: Int,
    val userId: Int = UserHandle.myUserId(),
    val keys: List<String>,
)

sealed interface RestrictedMode

object NoRestricted : RestrictedMode
data object NoRestricted : RestrictedMode

object BaseUserRestricted : RestrictedMode
data object BaseUserRestricted : RestrictedMode

interface BlockedByAdmin : RestrictedMode {
    fun getSummary(checked: Boolean?): String
@@ -79,6 +81,17 @@ interface RestrictionsProvider {

typealias RestrictionsProviderFactory = (Context, Restrictions) -> RestrictionsProvider

@Composable
internal fun RestrictionsProviderFactory.rememberRestrictedMode(
    restrictions: Restrictions,
): State<RestrictedMode?> {
    val context = LocalContext.current
    val restrictionsProvider = remember(restrictions) {
        this(context, restrictions)
    }
    return restrictionsProvider.restrictedModeState()
}

internal class RestrictionsProviderImpl(
    private val context: Context,
    private val restrictions: Restrictions,
+4 −4
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.settingslib.spaprivileged.model.app.userId
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
import com.android.settingslib.spaprivileged.model.enterprise.rememberRestrictedMode
import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
import kotlinx.coroutines.flow.Flow

@@ -149,14 +150,13 @@ internal class TogglePermissionInternalAppListModel<T : AppRecord>(

    @Composable
    fun getSummary(record: T): State<String> {
        val restrictionsProvider = remember(record.app.userId) {
            val restrictions = Restrictions(
        val restrictions = remember(record.app.userId) {
            Restrictions(
                userId = record.app.userId,
                keys = listModel.switchRestrictionKeys,
            )
            restrictionsProviderFactory(context, restrictions)
        }
        val restrictedMode = restrictionsProvider.restrictedModeState()
        val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions)
        val allowed = listModel.isAllowed(record)
        return remember {
            derivedStateOf {
+101 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.preference

import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
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.RestrictionsProviderFactory
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
import com.android.settingslib.spaprivileged.model.enterprise.rememberRestrictedMode

@Composable
fun RestrictedPreference(
    model: PreferenceModel,
    restrictions: Restrictions,
) {
    RestrictedPreference(model, restrictions, ::RestrictionsProviderImpl)
}

@VisibleForTesting
@Composable
internal fun RestrictedPreference(
    model: PreferenceModel,
    restrictions: Restrictions,
    restrictionsProviderFactory: RestrictionsProviderFactory,
) {
    if (restrictions.keys.isEmpty()) {
        Preference(model)
        return
    }
    val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions).value
    val restrictedSwitchModel = remember(restrictedMode) {
        RestrictedPreferenceModel(model, restrictedMode)
    }
    restrictedSwitchModel.RestrictionWrapper {
        Preference(restrictedSwitchModel)
    }
}

private class RestrictedPreferenceModel(
    model: PreferenceModel,
    private val restrictedMode: RestrictedMode?,
) : PreferenceModel {
    override val title = model.title
    override val summary = model.summary
    override val icon = model.icon

    override val enabled = when (restrictedMode) {
        NoRestricted -> model.enabled
        else -> stateOf(false)
    }

    override val onClick = when (restrictedMode) {
        NoRestricted -> model.onClick
        // Need to passthrough onClick for clickable semantics, although since enabled is false so
        // this will not be called.
        BaseUserRestricted -> model.onClick
        else -> null
    }

    @Composable
    fun RestrictionWrapper(content: @Composable () -> Unit) {
        if (restrictedMode !is BlockedByAdmin) {
            content()
            return
        }
        Box(
            Modifier
                .clickable(
                    role = Role.Button,
                    onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() },
                )
        ) { content() }
    }
}
+15 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settingslib.spaprivileged.template.preference

import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
@@ -40,22 +41,29 @@ import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
import com.android.settingslib.spaprivileged.model.enterprise.rememberRestrictedMode

@Composable
fun RestrictedSwitchPreference(
    model: SwitchPreferenceModel,
    restrictions: Restrictions,
    restrictionsProviderFactory: RestrictionsProviderFactory = ::RestrictionsProviderImpl,
) {
    RestrictedSwitchPreference(model, restrictions, ::RestrictionsProviderImpl)
}

@VisibleForTesting
@Composable
internal fun RestrictedSwitchPreference(
    model: SwitchPreferenceModel,
    restrictions: Restrictions,
    restrictionsProviderFactory: RestrictionsProviderFactory,
) {
    if (restrictions.keys.isEmpty()) {
        SwitchPreference(model)
        return
    }
    val context = LocalContext.current
    val restrictionsProvider = remember(restrictions) {
        restrictionsProviderFactory(context, restrictions)
    }
    val restrictedMode = restrictionsProvider.restrictedModeState().value
    val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions).value
    val restrictedSwitchModel = remember(restrictedMode) {
        RestrictedSwitchPreferenceModel(context, model, restrictedMode)
    }
@@ -112,8 +120,8 @@ private class RestrictedSwitchPreferenceModel(
    override val onCheckedChange = when (restrictedMode) {
        null -> null
        is NoRestricted -> model.onCheckedChange
        // Need to pass a non null onCheckedChange to enable semantics ToggleableState, although
        // since changeable is false this will not be called.
        // Need to passthrough onCheckedChange for toggleable semantics, although since changeable
        // is false so this will not be called.
        is BaseUserRestricted -> model.onCheckedChange
        // Pass null since semantics ToggleableState is provided in RestrictionWrapper.
        is BlockedByAdmin -> null
+5 −8
Original line number Diff line number Diff line
@@ -16,15 +16,15 @@

package com.android.settingslib.spaprivileged.template.scaffold

import androidx.annotation.VisibleForTesting
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.RestrictionsProviderFactory
import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
import com.android.settingslib.spaprivileged.model.enterprise.rememberRestrictedMode

@Composable
fun MoreOptionsScope.RestrictedMenuItem(
@@ -35,6 +35,7 @@ fun MoreOptionsScope.RestrictedMenuItem(
    RestrictedMenuItemImpl(text, restrictions, onClick, ::RestrictionsProviderImpl)
}

@VisibleForTesting
@Composable
internal fun MoreOptionsScope.RestrictedMenuItemImpl(
    text: String,
@@ -42,12 +43,8 @@ internal fun MoreOptionsScope.RestrictedMenuItemImpl(
    onClick: () -> Unit,
    restrictionsProviderFactory: RestrictionsProviderFactory,
) {
    val context = LocalContext.current
    val restrictionsProvider = remember(restrictions) {
        restrictionsProviderFactory(context, restrictions)
    }
    val restrictedMode = restrictionsProvider.restrictedModeState().value
    MenuItem(text = text, enabled = restrictedMode !is BaseUserRestricted) {
    val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions).value
    MenuItem(text = text, enabled = restrictedMode !== BaseUserRestricted) {
        when (restrictedMode) {
            is BlockedByAdmin -> restrictedMode.sendShowAdminSupportDetailsIntent()
            else -> onClick()
Loading