[Catalyst] Support Set API
Bug: 351941813
Flag: EXEMPT library
Test: Manual
Change-Id: I3620be77f3bb9354876946b0f4ef5006cf6f6d7f
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
index 04c2968..fdffe5d 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt
@@ -21,10 +21,11 @@
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 java.util.Locale
/** API to get preference graph. */
-abstract class GetPreferenceGraphApiHandler(private val activityClasses: Set<String>) :
+abstract class GetPreferenceGraphApiHandler :
ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
@@ -40,8 +41,9 @@
request: GetPreferenceGraphRequest,
): PreferenceGraphProto {
val builderRequest =
- if (request.activityClasses.isEmpty()) {
- GetPreferenceGraphRequest(activityClasses, request.visitedScreens, request.locale)
+ if (request.screenKeys.isEmpty()) {
+ val keys = PreferenceScreenRegistry.preferenceScreens.keys
+ GetPreferenceGraphRequest(keys, request.visitedScreens, request.locale)
} else {
request
}
@@ -52,14 +54,14 @@
/**
* Request of [GetPreferenceGraphApiHandler].
*
- * @param activityClasses activities of the preference graph
+ * @param screenKeys screen keys of the preference graph
* @param visitedScreens keys of the visited preference screen
* @param locale locale of the preference graph
*/
data class GetPreferenceGraphRequest
@JvmOverloads
constructor(
- val activityClasses: Set<String> = setOf(),
+ val screenKeys: Set<String> = setOf(),
val visitedScreens: Set<String> = setOf(),
val locale: Locale? = null,
val includeValue: Boolean = true,
@@ -68,25 +70,25 @@
object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
override fun encode(data: GetPreferenceGraphRequest): Bundle =
Bundle(3).apply {
- putStringArray(KEY_ACTIVITIES, data.activityClasses.toTypedArray())
- putStringArray(KEY_PREF_KEYS, data.visitedScreens.toTypedArray())
+ putStringArray(KEY_SCREEN_KEYS, data.screenKeys.toTypedArray())
+ putStringArray(KEY_VISITED_KEYS, data.visitedScreens.toTypedArray())
putString(KEY_LOCALE, data.locale?.toLanguageTag())
}
override fun decode(data: Bundle): GetPreferenceGraphRequest {
- val activities = data.getStringArray(KEY_ACTIVITIES) ?: arrayOf()
- val visitedScreens = data.getStringArray(KEY_PREF_KEYS) ?: arrayOf()
+ val screenKeys = data.getStringArray(KEY_SCREEN_KEYS) ?: arrayOf()
+ val visitedScreens = data.getStringArray(KEY_VISITED_KEYS) ?: arrayOf()
fun String?.toLocale() = if (this != null) Locale.forLanguageTag(this) else null
return GetPreferenceGraphRequest(
- activities.toSet(),
+ screenKeys.toSet(),
visitedScreens.toSet(),
data.getString(KEY_LOCALE).toLocale(),
)
}
- private const val KEY_ACTIVITIES = "activities"
- private const val KEY_PREF_KEYS = "keys"
- private const val KEY_LOCALE = "locale"
+ private const val KEY_SCREEN_KEYS = "k"
+ private const val KEY_VISITED_KEYS = "v"
+ private const val KEY_LOCALE = "l"
}
object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
@@ -96,5 +98,5 @@
override fun decode(data: Bundle): PreferenceGraphProto =
PreferenceGraphProto.parseFrom(data.getByteArray(KEY_GRAPH)!!)
- private const val KEY_GRAPH = "graph"
+ private const val KEY_GRAPH = "g"
}
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
index 8fb16d8..5e78a29 100644
--- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt
@@ -19,14 +19,12 @@
package com.android.settingslib.graph
import android.annotation.SuppressLint
-import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
-import android.preference.PreferenceActivity
import android.util.Log
import androidx.fragment.app.Fragment
import androidx.preference.Preference
@@ -53,18 +51,13 @@
import com.android.settingslib.metadata.PreferenceTitleProvider
import com.android.settingslib.preference.PreferenceScreenFactory
import com.android.settingslib.preference.PreferenceScreenProvider
-import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+import java.util.Locale
private const val TAG = "PreferenceGraphBuilder"
-/**
- * Builder of preference graph.
- *
- * Only activity in current application is supported. To create preference graph across
- * applications, use [crawlPreferenceGraph].
- */
+/** Builder of preference graph. */
class PreferenceGraphBuilder
private constructor(private val context: Context, private val request: GetPreferenceGraphRequest) {
private val preferenceScreenFactory by lazy {
@@ -75,21 +68,13 @@
private val includeValue = request.includeValue
private suspend fun init() {
- for (activityClass in request.activityClasses) {
- add(activityClass)
- }
- // Temporarily add all screens
- for (key in PreferenceScreenRegistry.preferenceScreens.keys) {
- addPreferenceScreenFromRegistry(key, Activity::class.java)
+ for (key in request.screenKeys) {
+ addPreferenceScreenFromRegistry(key)
}
}
fun build() = builder.build()
- /** Adds an activity to the graph. */
- suspend fun <T> add(activityClass: Class<T>) where T : Activity, T : PreferenceScreenProvider =
- addPreferenceScreenProvider(activityClass)
-
/**
* Adds an activity to the graph.
*
@@ -100,8 +85,10 @@
try {
val intent = Intent()
intent.setClassName(context, activityClassName)
- if (context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) ==
- null) {
+ if (
+ context.packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) ==
+ null
+ ) {
Log.e(TAG, "$activityClassName is not activity")
return
}
@@ -122,7 +109,7 @@
return false
}
val key = getPreferenceScreenKey { activityClass.newInstance() } ?: return false
- if (addPreferenceScreenFromRegistry(key, activityClass)) {
+ if (addPreferenceScreenFromRegistry(key)) {
builder.addRoots(key)
return true
}
@@ -144,23 +131,16 @@
null
}
- private suspend fun addPreferenceScreenFromRegistry(
- key: String,
- activityClass: Class<*>,
- ): Boolean {
+ private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean {
val metadata = PreferenceScreenRegistry[key] ?: return false
- if (!metadata.hasCompleteHierarchy()) return false
- return addPreferenceScreenMetadata(metadata, activityClass)
+ return addPreferenceScreenMetadata(metadata)
}
- private suspend fun addPreferenceScreenMetadata(
- metadata: PreferenceScreenMetadata,
- activityClass: Class<*>,
- ): Boolean =
- addPreferenceScreen(metadata.key, activityClass) {
+ private suspend fun addPreferenceScreenMetadata(metadata: PreferenceScreenMetadata): Boolean =
+ addPreferenceScreen(metadata.key) {
preferenceScreenProto {
- completeHierarchy = true
- root = metadata.getPreferenceHierarchy(context).toProto(activityClass, true)
+ completeHierarchy = metadata.hasCompleteHierarchy()
+ root = metadata.getPreferenceHierarchy(context).toProto(true)
}
}
@@ -168,7 +148,7 @@
Log.d(TAG, "add $activityClass")
createPreferenceScreen { activityClass.newInstance() }
?.let {
- addPreferenceScreen(Intent(context, activityClass), activityClass, it)
+ addPreferenceScreen(Intent(context, activityClass), it)
builder.addRoots(it.key)
}
}
@@ -195,106 +175,85 @@
return@withContext null
}
- private suspend fun addPreferenceScreen(
- intent: Intent,
- activityClass: Class<*>,
- preferenceScreen: PreferenceScreen?,
- ) {
+ private suspend fun addPreferenceScreen(intent: Intent, preferenceScreen: PreferenceScreen?) {
val key = preferenceScreen?.key
if (key.isNullOrEmpty()) {
- Log.e(TAG, "$activityClass \"$preferenceScreen\" has no key")
+ Log.e(TAG, "\"$preferenceScreen\" has no key")
return
}
- @Suppress("CheckReturnValue")
- addPreferenceScreen(key, activityClass) { preferenceScreen.toProto(intent, activityClass) }
+ @Suppress("CheckReturnValue") addPreferenceScreen(key) { preferenceScreen.toProto(intent) }
}
private suspend fun addPreferenceScreen(
key: String,
- activityClass: Class<*>,
preferenceScreenProvider: suspend () -> PreferenceScreenProto,
- ): Boolean {
- if (!visitedScreens.add(key)) {
- Log.w(TAG, "$activityClass $key visited")
- return false
- }
- val activityClassName = activityClass.name
- val associatedKey = builder.getActivityScreensOrDefault(activityClassName, null)
- if (associatedKey == null) {
- builder.putActivityScreens(activityClassName, key)
- } else if (associatedKey != key) {
- Log.w(TAG, "Dup $activityClassName association, old: $associatedKey, new: $key")
- }
- builder.putScreens(key, preferenceScreenProvider())
- return true
- }
-
- private suspend fun PreferenceScreen.toProto(
- intent: Intent,
- activityClass: Class<*>,
- ): PreferenceScreenProto = preferenceScreenProto {
- this.intent = intent.toProto()
- root = (this@toProto as PreferenceGroup).toProto(activityClass)
- }
-
- private suspend fun PreferenceGroup.toProto(activityClass: Class<*>): PreferenceGroupProto =
- preferenceGroupProto {
- preference = (this@toProto as Preference).toProto(activityClass)
- for (index in 0 until preferenceCount) {
- val child = getPreference(index)
- addPreferences(
- preferenceOrGroupProto {
- if (child is PreferenceGroup) {
- group = child.toProto(activityClass)
- } else {
- preference = child.toProto(activityClass)
- }
- })
- }
+ ): Boolean =
+ if (visitedScreens.add(key)) {
+ builder.putScreens(key, preferenceScreenProvider())
+ true
+ } else {
+ Log.w(TAG, "$key visited")
+ false
}
- private suspend fun Preference.toProto(activityClass: Class<*>): PreferenceProto =
- preferenceProto {
- this@toProto.key?.let { key = it }
- this@toProto.title?.let { title = textProto { string = it.toString() } }
- this@toProto.summary?.let { summary = textProto { string = it.toString() } }
- val preferenceExtras = peekExtras()
- preferenceExtras?.let { extras = it.toProto() }
- enabled = isEnabled
- available = isVisible
- persistent = isPersistent
- if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
- value = preferenceValueProto { booleanValue = this@toProto.isChecked }
- }
- this@toProto.fragment.toActionTarget(activityClass, preferenceExtras)?.let {
- actionTarget = it
- return@preferenceProto
- }
- this@toProto.intent?.let { actionTarget = it.toActionTarget() }
+ private suspend fun PreferenceScreen.toProto(intent: Intent?): PreferenceScreenProto =
+ preferenceScreenProto {
+ intent?.let { this.intent = it.toProto() }
+ root = (this@toProto as PreferenceGroup).toProto()
}
- private suspend fun PreferenceHierarchy.toProto(
- activityClass: Class<*>,
- isRoot: Boolean,
- ): PreferenceGroupProto = preferenceGroupProto {
- preference = toProto(this@toProto, activityClass, isRoot)
- forEachAsync {
+ private suspend fun PreferenceGroup.toProto(): PreferenceGroupProto = preferenceGroupProto {
+ preference = (this@toProto as Preference).toProto()
+ for (index in 0 until preferenceCount) {
+ val child = getPreference(index)
addPreferences(
preferenceOrGroupProto {
- if (it is PreferenceHierarchy) {
- group = it.toProto(activityClass, false)
+ if (child is PreferenceGroup) {
+ group = child.toProto()
} else {
- preference = toProto(it, activityClass, false)
+ preference = child.toProto()
}
- })
+ }
+ )
}
}
- private suspend fun toProto(
- node: PreferenceHierarchyNode,
- activityClass: Class<*>,
- isRoot: Boolean,
- ) = preferenceProto {
+ private suspend fun Preference.toProto(): PreferenceProto = preferenceProto {
+ this@toProto.key?.let { key = it }
+ this@toProto.title?.let { title = textProto { string = it.toString() } }
+ this@toProto.summary?.let { summary = textProto { string = it.toString() } }
+ val preferenceExtras = peekExtras()
+ preferenceExtras?.let { extras = it.toProto() }
+ enabled = isEnabled
+ available = isVisible
+ persistent = isPersistent
+ if (includeValue && isPersistent && this@toProto is TwoStatePreference) {
+ value = preferenceValueProto { booleanValue = this@toProto.isChecked }
+ }
+ this@toProto.fragment.toActionTarget(preferenceExtras)?.let {
+ actionTarget = it
+ return@preferenceProto
+ }
+ this@toProto.intent?.let { actionTarget = it.toActionTarget() }
+ }
+
+ private suspend fun PreferenceHierarchy.toProto(isRoot: Boolean): PreferenceGroupProto =
+ preferenceGroupProto {
+ preference = toProto(this@toProto, isRoot)
+ forEachAsync {
+ addPreferences(
+ preferenceOrGroupProto {
+ if (it is PreferenceHierarchy) {
+ group = it.toProto(false)
+ } else {
+ preference = toProto(it, false)
+ }
+ }
+ )
+ }
+ }
+
+ private suspend fun toProto(node: PreferenceHierarchyNode, isRoot: Boolean) = preferenceProto {
val metadata = node.metadata
key = metadata.key
metadata.getTitleTextProto(isRoot)?.let { title = it }
@@ -318,22 +277,18 @@
restricted = metadata.isRestricted(context)
}
persistent = metadata.isPersistent(context)
- if (includeValue &&
- persistent &&
- metadata is BooleanValue &&
- metadata is PersistentPreference<*>) {
+ if (
+ includeValue &&
+ persistent &&
+ metadata is BooleanValue &&
+ metadata is PersistentPreference<*>
+ ) {
metadata.storage(context).getValue(metadata.key, Boolean::class.javaObjectType)?.let {
value = preferenceValueProto { booleanValue = it }
}
}
if (metadata is PreferenceScreenMetadata) {
- if (metadata.hasCompleteHierarchy()) {
- @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata, activityClass)
- } else {
- metadata.fragmentClass()?.toActionTarget(activityClass, preferenceExtras)?.let {
- actionTarget = it
- }
- }
+ @Suppress("CheckReturnValue") addPreferenceScreenMetadata(metadata)
}
metadata.intent(context)?.let { actionTarget = it.toActionTarget() }
}
@@ -359,16 +314,13 @@
}
}
- private suspend fun String?.toActionTarget(
- activityClass: Class<*>,
- extras: Bundle?,
- ): ActionTarget? {
+ private suspend fun String?.toActionTarget(extras: Bundle?): ActionTarget? {
if (this.isNullOrEmpty()) return null
try {
val fragmentClass = context.classLoader.loadClass(this)
if (Fragment::class.java.isAssignableFrom(fragmentClass)) {
@Suppress("UNCHECKED_CAST")
- return (fragmentClass as Class<out Fragment>).toActionTarget(activityClass, extras)
+ return (fragmentClass as Class<out Fragment>).toActionTarget(extras)
}
} catch (e: Exception) {
Log.e(TAG, "Cannot loadClass $this", e)
@@ -376,16 +328,12 @@
return null
}
- private suspend fun Class<out Fragment>.toActionTarget(
- activityClass: Class<*>,
- extras: Bundle?,
- ): ActionTarget {
- val startIntent = Intent(context, activityClass)
- startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, name)
- extras?.let { startIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, it) }
- if (!PreferenceScreenProvider::class.java.isAssignableFrom(this) &&
- !PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(this)) {
- return actionTargetProto { intent = startIntent.toProto() }
+ private suspend fun Class<out Fragment>.toActionTarget(extras: Bundle?): ActionTarget? {
+ if (
+ !PreferenceScreenProvider::class.java.isAssignableFrom(this) &&
+ !PreferenceScreenBindingKeyProvider::class.java.isAssignableFrom(this)
+ ) {
+ return null
}
val fragment =
withContext(Dispatchers.Main) {
@@ -398,18 +346,24 @@
}
if (fragment is PreferenceScreenBindingKeyProvider) {
val screenKey = fragment.getPreferenceScreenBindingKey(context)
- if (screenKey != null && addPreferenceScreenFromRegistry(screenKey, activityClass)) {
+ if (screenKey != null && addPreferenceScreenFromRegistry(screenKey)) {
return actionTargetProto { key = screenKey }
}
}
if (fragment is PreferenceScreenProvider) {
- val screen = fragment.createPreferenceScreen(preferenceScreenFactory)
- if (screen != null) {
- addPreferenceScreen(startIntent, activityClass, screen)
- return actionTargetProto { key = screen.key }
+ try {
+ val screen = fragment.createPreferenceScreen(preferenceScreenFactory)
+ val screenKey = screen?.key
+ if (!screenKey.isNullOrEmpty()) {
+ @Suppress("CheckReturnValue")
+ addPreferenceScreen(screenKey) { screen.toProto(null) }
+ return actionTargetProto { key = screenKey }
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Fail to createPreferenceScreen for $fragment", e)
}
}
- return actionTargetProto { intent = startIntent.toProto() }
+ return null
}
private suspend fun Intent.toActionTarget(): ActionTarget {
diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
new file mode 100644
index 0000000..d8db1bb
--- /dev/null
+++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 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.graph
+
+import android.app.Application
+import android.os.Bundle
+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.IntMessageCodec
+import com.android.settingslib.ipc.MessageCodec
+import com.android.settingslib.metadata.BooleanValue
+import com.android.settingslib.metadata.PersistentPreference
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceRestrictionProvider
+import com.android.settingslib.metadata.PreferenceScreenRegistry
+import com.android.settingslib.metadata.ReadWritePermit
+
+/** Request to set preference value. */
+data class PreferenceSetterRequest(
+ val screenKey: String,
+ val key: String,
+ val value: PreferenceValueProto,
+)
+
+/** Result of preference setter request. */
+@IntDef(
+ PreferenceSetterResult.OK,
+ PreferenceSetterResult.UNSUPPORTED,
+ PreferenceSetterResult.DISABLED,
+ PreferenceSetterResult.UNAVAILABLE,
+ PreferenceSetterResult.INVALID_REQUEST,
+ PreferenceSetterResult.INTERNAL_ERROR,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class PreferenceSetterResult {
+ companion object {
+ /** Set preference value successfully. */
+ const val OK = 0
+ /** Set preference value is unsupported on the preference. */
+ const val UNSUPPORTED = 1
+ /** Preference is disabled and cannot set preference value. */
+ const val DISABLED = 2
+ /** Preference is restricted by managed configuration and cannot set preference value. */
+ const val RESTRICTED = 3
+ /** Preference is unavailable and cannot set preference value. */
+ const val UNAVAILABLE = 4
+ /** Require (runtime/special) app permission from user explicitly. */
+ const val REQUIRE_APP_PERMISSION = 5
+ /** Require explicit user agreement (e.g. terms of service). */
+ const val REQUIRE_USER_AGREEMENT = 6
+ /** Disallow to set preference value (e.g. uid not allowed). */
+ const val DISALLOW = 7
+ /** Request is invalid. */
+ const val INVALID_REQUEST = 8
+ /** Internal error happened when persist preference value. */
+ const val INTERNAL_ERROR = 9
+ }
+}
+
+/** Preference setter API descriptor. */
+class PreferenceSetterApiDescriptor(override val id: Int) :
+ ApiDescriptor<PreferenceSetterRequest, Int> {
+
+ override val requestCodec: MessageCodec<PreferenceSetterRequest>
+ get() = PreferenceSetterRequestCodec
+
+ override val responseCodec: MessageCodec<Int>
+ get() = IntMessageCodec
+}
+
+/** Preference setter API implementation. */
+class PreferenceSetterApiHandler(override val id: Int) : ApiHandler<PreferenceSetterRequest, Int> {
+
+ override fun hasPermission(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: PreferenceSetterRequest,
+ ): Boolean = true
+
+ override suspend fun invoke(
+ application: Application,
+ myUid: Int,
+ callingUid: Int,
+ request: PreferenceSetterRequest,
+ ): Int {
+ val screenMetadata =
+ PreferenceScreenRegistry[request.screenKey] ?: return PreferenceSetterResult.UNSUPPORTED
+ val key = request.key
+ val metadata =
+ screenMetadata.getPreferenceHierarchy(application).find(key)
+ ?: return PreferenceSetterResult.UNSUPPORTED
+ if (metadata !is PersistentPreference<*>) return PreferenceSetterResult.UNSUPPORTED
+ if (!metadata.isEnabled(application)) return PreferenceSetterResult.DISABLED
+ if (metadata is PreferenceRestrictionProvider && metadata.isRestricted(application)) {
+ return PreferenceSetterResult.RESTRICTED
+ }
+ if (metadata is PreferenceAvailabilityProvider && !metadata.isAvailable(application)) {
+ return PreferenceSetterResult.UNAVAILABLE
+ }
+ val storage = metadata.storage(application)
+ val value = request.value
+ try {
+ if (value.hasBooleanValue()) {
+ if (metadata !is BooleanValue) return PreferenceSetterResult.INVALID_REQUEST
+ val booleanValue = value.booleanValue
+ @Suppress("UNCHECKED_CAST")
+ val booleanPreference = metadata as PersistentPreference<Boolean>
+ when (
+ booleanPreference.getWritePermit(application, booleanValue, myUid, callingUid)
+ ) {
+ ReadWritePermit.ALLOW -> {}
+ ReadWritePermit.DISALLOW -> return PreferenceSetterResult.DISALLOW
+ ReadWritePermit.REQUIRE_APP_PERMISSION ->
+ return PreferenceSetterResult.REQUIRE_APP_PERMISSION
+ ReadWritePermit.REQUIRE_USER_AGREEMENT ->
+ return PreferenceSetterResult.REQUIRE_USER_AGREEMENT
+ else -> return PreferenceSetterResult.INTERNAL_ERROR
+ }
+ storage.setValue(key, Boolean::class.javaObjectType, booleanValue)
+ return PreferenceSetterResult.OK
+ }
+ } catch (e: Exception) {
+ return PreferenceSetterResult.INTERNAL_ERROR
+ }
+ return PreferenceSetterResult.INVALID_REQUEST
+ }
+
+ override val requestCodec: MessageCodec<PreferenceSetterRequest>
+ get() = PreferenceSetterRequestCodec
+
+ override val responseCodec: MessageCodec<Int>
+ get() = IntMessageCodec
+}
+
+/** Message codec for [PreferenceSetterRequest]. */
+object PreferenceSetterRequestCodec : MessageCodec<PreferenceSetterRequest> {
+ override fun encode(data: PreferenceSetterRequest) =
+ Bundle(3).apply {
+ putString(SCREEN_KEY, data.screenKey)
+ putString(KEY, data.key)
+ putByteArray(null, data.value.toByteArray())
+ }
+
+ override fun decode(data: Bundle) =
+ PreferenceSetterRequest(
+ data.getString(SCREEN_KEY)!!,
+ data.getString(KEY)!!,
+ PreferenceValueProto.parseFrom(data.getByteArray(null)!!),
+ )
+
+ private const val SCREEN_KEY = "s"
+ private const val KEY = "k"
+}
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
index 95661c9..6e38df1 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt
@@ -21,8 +21,8 @@
import com.android.settingslib.graph.GetPreferenceGraphRequest
/** Api to get preference graph. */
-internal class PreferenceGraphApi(activityClasses: Set<String>) :
- GetPreferenceGraphApiHandler(activityClasses) {
+internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() {
+
override val id: Int
get() = API_GET_PREFERENCE_GRAPH
@@ -31,7 +31,5 @@
myUid: Int,
callingUid: Int,
request: GetPreferenceGraphRequest,
- ): Boolean {
- return true // TODO: add permission check
- }
+ ) = true
}
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
index d382dad..8ebb145 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt
@@ -16,6 +16,7 @@
package com.android.settingslib.service
+import com.android.settingslib.graph.PreferenceSetterApiHandler
import com.android.settingslib.ipc.ApiHandler
import com.android.settingslib.ipc.MessengerService
import com.android.settingslib.ipc.PermissionChecker
@@ -31,7 +32,10 @@
name: String = "PreferenceService",
) :
MessengerService(
- listOf<ApiHandler<*, *>>(PreferenceGraphApi(setOf())),
+ listOf<ApiHandler<*, *>>(
+ PreferenceGraphApi(),
+ PreferenceSetterApiHandler(API_PREFERENCE_SETTER),
+ ),
permissionChecker,
name,
)
diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
index 8f03111..1f38a66 100644
--- a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
+++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt
@@ -19,3 +19,4 @@
const val PREFERENCE_SERVICE_ACTION = "com.android.settingslib.PREFERENCE_SERVICE"
internal const val API_GET_PREFERENCE_GRAPH = 1
+internal const val API_PREFERENCE_SETTER = 2