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

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

Merge changes from topic "catalyst" into main

* changes:
  [Catalyst] Add ApiPermissionChecker and refactor code for preference service
  [Catalyst] Sync libraries
parents 8ac0405b b7f0734c
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -22,11 +22,13 @@ import com.android.settingslib.graph.proto.PreferenceGraphProto
import com.android.settingslib.ipc.ApiHandler
import com.android.settingslib.ipc.MessageCodec
import com.android.settingslib.metadata.PreferenceScreenRegistry
import com.android.settingslib.preference.PreferenceScreenProvider
import java.util.Locale

/** API to get preference graph. */
abstract class GetPreferenceGraphApiHandler :
    ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
abstract class GetPreferenceGraphApiHandler(
    private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>
) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {

    override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
        get() = GetPreferenceGraphRequestCodec
@@ -40,14 +42,16 @@ abstract class GetPreferenceGraphApiHandler :
        callingUid: Int,
        request: GetPreferenceGraphRequest,
    ): PreferenceGraphProto {
        val builderRequest =
        val builder = PreferenceGraphBuilder.of(application, request)
        if (request.screenKeys.isEmpty()) {
                val keys = PreferenceScreenRegistry.preferenceScreens.keys
                GetPreferenceGraphRequest(keys, request.visitedScreens, request.locale)
            } else {
                request
            for (key in PreferenceScreenRegistry.preferenceScreens.keys) {
                builder.addPreferenceScreenFromRegistry(key)
            }
        return PreferenceGraphBuilder.of(application, builderRequest).build()
            for (provider in preferenceScreenProviders) {
                builder.addPreferenceScreenProvider(provider)
            }
        }
        return builder.build()
    }
}

+2 −2
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ private constructor(private val context: Context, private val request: GetPrefer
            null
        }

    private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
    suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
        val metadata = PreferenceScreenRegistry[key] ?: return false
        return addPreferenceScreenMetadata(metadata)
    }
@@ -146,7 +146,7 @@ private constructor(private val context: Context, private val request: GetPrefer
            }
        }

    private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
    suspend fun addPreferenceScreenProvider(activityClass: Class<*>) {
        Log.d(TAG, "add $activityClass")
        createPreferenceScreen { activityClass.newInstance() }
            ?.let {
+10 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import androidx.annotation.IntDef
import com.android.settingslib.graph.proto.PreferenceValueProto
import com.android.settingslib.ipc.ApiDescriptor
import com.android.settingslib.ipc.ApiHandler
import com.android.settingslib.ipc.ApiPermissionChecker
import com.android.settingslib.ipc.IntMessageCodec
import com.android.settingslib.ipc.MessageCodec
import com.android.settingslib.metadata.BooleanValue
@@ -45,7 +46,11 @@ data class PreferenceSetterRequest(
    PreferenceSetterResult.OK,
    PreferenceSetterResult.UNSUPPORTED,
    PreferenceSetterResult.DISABLED,
    PreferenceSetterResult.RESTRICTED,
    PreferenceSetterResult.UNAVAILABLE,
    PreferenceSetterResult.REQUIRE_APP_PERMISSION,
    PreferenceSetterResult.REQUIRE_USER_AGREEMENT,
    PreferenceSetterResult.DISALLOW,
    PreferenceSetterResult.INVALID_REQUEST,
    PreferenceSetterResult.INTERNAL_ERROR,
)
@@ -87,14 +92,17 @@ class PreferenceSetterApiDescriptor(override val id: Int) :
}

/** Preference setter API implementation. */
class PreferenceSetterApiHandler(override val id: Int) : ApiHandler<PreferenceSetterRequest, Int> {
class PreferenceSetterApiHandler(
    override val id: Int,
    private val permissionChecker: ApiPermissionChecker<PreferenceSetterRequest>,
) : ApiHandler<PreferenceSetterRequest, Int> {

    override fun hasPermission(
        application: Application,
        myUid: Int,
        callingUid: Int,
        request: PreferenceSetterRequest,
    ): Boolean = true
    ) = permissionChecker.hasPermission(application, myUid, callingUid, request)

    override suspend fun invoke(
        application: Application,
+30 −10
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.settingslib.graph

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import com.android.settingslib.graph.proto.BundleProto
import com.android.settingslib.graph.proto.BundleProto.BundleValue
@@ -42,6 +44,20 @@ fun Intent.toProto(): IntentProto = intentProto {
    this@toProto.type?.let { mimeType = it }
}

fun IntentProto.toIntent(): Intent? {
    if (!hasComponent()) return null
    val componentName = ComponentName.unflattenFromString(component) ?: return null
    val intent = Intent()
    intent.component = componentName
    if (hasAction()) intent.action = action
    if (hasData()) intent.data = Uri.parse(data)
    if (hasPkg()) intent.`package` = pkg
    if (hasFlags()) intent.flags = flags
    if (hasExtras()) intent.putExtras(extras.toBundle())
    if (hasMimeType()) intent.setType(mimeType)
    return intent
}

fun Bundle.toProto(): BundleProto = bundleProto {
    fun toProto(value: Any): BundleValue = bundleValueProto {
        when (value) {
@@ -61,14 +77,18 @@ fun Bundle.toProto(): BundleProto = bundleProto {
    }
}

fun BundleValue.stringify(): String =
fun BundleProto.toBundle(): Bundle =
    Bundle().apply {
        for ((key, value) in valuesMap) {
            when {
        hasBooleanValue() -> "$valueCase"
        hasBytesValue() -> "$bytesValue"
        hasIntValue() -> "$intValue"
        hasLongValue() -> "$longValue"
        hasStringValue() -> stringValue
        hasDoubleValue() -> "$doubleValue"
        hasBundleValue() -> "$bundleValue"
        else -> "Unknown"
                value.hasBooleanValue() -> putBoolean(key, value.booleanValue)
                value.hasBytesValue() -> putByteArray(key, value.bytesValue.toByteArray())
                value.hasIntValue() -> putInt(key, value.intValue)
                value.hasLongValue() -> putLong(key, value.longValue)
                value.hasStringValue() -> putString(key, value.stringValue)
                value.hasDoubleValue() -> putDouble(key, value.doubleValue)
                value.hasBundleValue() -> putBundle(key, value.bundleValue.toBundle())
                else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value")
            }
        }
    }
+23 −12
Original line number Diff line number Diff line
@@ -56,6 +56,27 @@ interface ApiDescriptor<Request, Response> {
    val responseCodec: MessageCodec<Response>
}

/** Permission checker for api. */
fun interface ApiPermissionChecker<R> {
    /**
     * Returns if the request is permitted.
     *
     * @param application application context
     * @param myUid uid of current process
     * @param callingUid uid of peer process
     * @param request API request
     * @return `false` if permission is denied, otherwise `true`
     */
    fun hasPermission(application: Application, myUid: Int, callingUid: Int, request: R): Boolean

    companion object {
        private val ALWAYS_ALLOW = ApiPermissionChecker<Any> { _, _, _, _ -> true }

        @Suppress("UNCHECKED_CAST")
        fun <T> alwaysAllow(): ApiPermissionChecker<T> = ALWAYS_ALLOW as ApiPermissionChecker<T>
    }
}

/**
 * Handler of API.
 *
@@ -64,18 +85,8 @@ interface ApiDescriptor<Request, Response> {
 *
 * The implementation must be threadsafe.
 */
interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> {
    /**
     * Returns if the request is permitted.
     *
     * @return `false` if permission is denied, otherwise `true`
     */
    fun hasPermission(
        application: Application,
        myUid: Int,
        callingUid: Int,
        request: Request,
    ): Boolean
interface ApiHandler<Request, Response> :
    ApiDescriptor<Request, Response>, ApiPermissionChecker<Request> {

    /**
     * Invokes the API.
Loading