Support GetMetadata for Preference Service
Bug: 379750656 Flag: com.android.settingslib.flags.settings_catalyst Test: unit test Change-Id: Ia9b438360b60ff509a259df0a079ec4d745fb595
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.service
|
package com.android.settings.service
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.OutcomeReceiver
|
import android.os.OutcomeReceiver
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
@@ -26,38 +27,49 @@ import android.service.settings.preferences.MetadataResult
|
|||||||
import android.service.settings.preferences.SetValueRequest
|
import android.service.settings.preferences.SetValueRequest
|
||||||
import android.service.settings.preferences.SetValueResult
|
import android.service.settings.preferences.SetValueResult
|
||||||
import android.service.settings.preferences.SettingsPreferenceService
|
import android.service.settings.preferences.SettingsPreferenceService
|
||||||
|
import com.android.settingslib.graph.GetPreferenceGraphApiHandler
|
||||||
|
import com.android.settingslib.graph.GetPreferenceGraphRequest
|
||||||
import com.android.settingslib.graph.PreferenceGetterApiHandler
|
import com.android.settingslib.graph.PreferenceGetterApiHandler
|
||||||
|
import com.android.settingslib.graph.PreferenceGetterFlags
|
||||||
import com.android.settingslib.graph.PreferenceSetterApiHandler
|
import com.android.settingslib.graph.PreferenceSetterApiHandler
|
||||||
import com.android.settingslib.ipc.ApiPermissionChecker
|
import com.android.settingslib.ipc.ApiPermissionChecker
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
class PreferenceService : SettingsPreferenceService() {
|
class PreferenceService : SettingsPreferenceService() {
|
||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
private val getApiHandler = PreferenceGetterApiHandler(1, ApiPermissionChecker.alwaysAllow())
|
private val getApiHandler = PreferenceGetterApiHandler(1, ApiPermissionChecker.alwaysAllow())
|
||||||
private val setApiHandler = PreferenceSetterApiHandler(2, ApiPermissionChecker.alwaysAllow())
|
private val setApiHandler = PreferenceSetterApiHandler(2, ApiPermissionChecker.alwaysAllow())
|
||||||
|
private val graphApi = GraphProvider(3)
|
||||||
|
|
||||||
override fun onGetAllPreferenceMetadata(
|
override fun onGetAllPreferenceMetadata(
|
||||||
request: MetadataRequest,
|
request: MetadataRequest,
|
||||||
callback: OutcomeReceiver<MetadataResult, Exception>
|
callback: OutcomeReceiver<MetadataResult, Exception>
|
||||||
) {
|
) {
|
||||||
// TODO(379750656): Update graph API to be usable outside SettingsLib
|
scope.launch {
|
||||||
callback.onError(UnsupportedOperationException("Not yet supported"))
|
val graphProto = graphApi.invoke(application, Process.myUid(), Binder.getCallingUid(),
|
||||||
|
GetPreferenceGraphRequest(
|
||||||
|
includeValue = false,
|
||||||
|
flags = PreferenceGetterFlags.METADATA
|
||||||
|
))
|
||||||
|
val result = transformCatalystGetMetadataResponse(this@PreferenceService, graphProto)
|
||||||
|
callback.onResult(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onGetPreferenceValue(
|
override fun onGetPreferenceValue(
|
||||||
request: GetValueRequest,
|
request: GetValueRequest,
|
||||||
callback: OutcomeReceiver<GetValueResult, Exception>
|
callback: OutcomeReceiver<GetValueResult, Exception>
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch {
|
||||||
val apiRequest = transformFrameworkGetValueRequest(request)
|
val apiRequest = transformFrameworkGetValueRequest(request)
|
||||||
val response = getApiHandler.invoke(application, Process.myUid(),
|
val response = getApiHandler.invoke(application, Process.myUid(),
|
||||||
Binder.getCallingPid(), apiRequest)
|
Binder.getCallingUid(), apiRequest)
|
||||||
val result = transformCatalystGetValueResponse(
|
val result = transformCatalystGetValueResponse(
|
||||||
this@PreferenceService,
|
this@PreferenceService,
|
||||||
request,
|
request,
|
||||||
@@ -75,7 +87,7 @@ class PreferenceService : SettingsPreferenceService() {
|
|||||||
request: SetValueRequest,
|
request: SetValueRequest,
|
||||||
callback: OutcomeReceiver<SetValueResult, Exception>
|
callback: OutcomeReceiver<SetValueResult, Exception>
|
||||||
) {
|
) {
|
||||||
scope.launch(Dispatchers.IO) {
|
scope.launch {
|
||||||
val apiRequest = transformFrameworkSetValueRequest(request)
|
val apiRequest = transformFrameworkSetValueRequest(request)
|
||||||
if (apiRequest == null) {
|
if (apiRequest == null) {
|
||||||
callback.onResult(
|
callback.onResult(
|
||||||
@@ -83,10 +95,20 @@ class PreferenceService : SettingsPreferenceService() {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val response = setApiHandler.invoke(application, Process.myUid(),
|
val response = setApiHandler.invoke(application, Process.myUid(),
|
||||||
Binder.getCallingPid(), apiRequest)
|
Binder.getCallingUid(), apiRequest)
|
||||||
|
|
||||||
callback.onResult(transformCatalystSetValueResponse(response))
|
callback.onResult(transformCatalystSetValueResponse(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic implementation - we already have permission to access Graph for Metadata via superclass
|
||||||
|
private class GraphProvider(override val id: Int) : GetPreferenceGraphApiHandler(emptySet()) {
|
||||||
|
override fun hasPermission(
|
||||||
|
application: Application,
|
||||||
|
myUid: Int,
|
||||||
|
callingUid: Int,
|
||||||
|
request: GetPreferenceGraphRequest
|
||||||
|
) = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ package com.android.settings.service
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.service.settings.preferences.GetValueRequest
|
import android.service.settings.preferences.GetValueRequest
|
||||||
import android.service.settings.preferences.GetValueResult
|
import android.service.settings.preferences.GetValueResult
|
||||||
|
import android.service.settings.preferences.MetadataResult
|
||||||
import android.service.settings.preferences.SetValueRequest
|
import android.service.settings.preferences.SetValueRequest
|
||||||
import android.service.settings.preferences.SetValueResult
|
import android.service.settings.preferences.SetValueResult
|
||||||
import android.service.settings.preferences.SettingsPreferenceMetadata
|
import android.service.settings.preferences.SettingsPreferenceMetadata
|
||||||
@@ -34,9 +35,55 @@ import com.android.settingslib.graph.preferenceValueProto
|
|||||||
import com.android.settingslib.graph.proto.PreferenceProto
|
import com.android.settingslib.graph.proto.PreferenceProto
|
||||||
import com.android.settingslib.graph.proto.PreferenceValueProto
|
import com.android.settingslib.graph.proto.PreferenceValueProto
|
||||||
import com.android.settingslib.graph.getText
|
import com.android.settingslib.graph.getText
|
||||||
|
import com.android.settingslib.graph.proto.PreferenceGraphProto
|
||||||
|
import com.android.settingslib.graph.proto.PreferenceOrGroupProto
|
||||||
import com.android.settingslib.graph.toIntent
|
import com.android.settingslib.graph.toIntent
|
||||||
import com.android.settingslib.metadata.SensitivityLevel
|
import com.android.settingslib.metadata.SensitivityLevel
|
||||||
|
|
||||||
|
/** Transform Catalyst Graph result to Framework GET METADATA result */
|
||||||
|
fun transformCatalystGetMetadataResponse(
|
||||||
|
context: Context,
|
||||||
|
graph: PreferenceGraphProto
|
||||||
|
): MetadataResult {
|
||||||
|
val preferences = mutableSetOf<PreferenceWithScreen>()
|
||||||
|
// recursive function to visit all nodes in preference group
|
||||||
|
fun traverseGroupOrPref(
|
||||||
|
screenKey: String,
|
||||||
|
groupOrPref: PreferenceOrGroupProto,
|
||||||
|
) {
|
||||||
|
when (groupOrPref.kindCase) {
|
||||||
|
PreferenceOrGroupProto.KindCase.PREFERENCE ->
|
||||||
|
preferences.add(
|
||||||
|
PreferenceWithScreen(screenKey, groupOrPref.preference)
|
||||||
|
)
|
||||||
|
PreferenceOrGroupProto.KindCase.GROUP -> {
|
||||||
|
for (child in groupOrPref.group.preferencesList) {
|
||||||
|
traverseGroupOrPref(screenKey, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// traverse all screens and all preferences on screen
|
||||||
|
for ((screenKey, screen) in graph.screensMap) {
|
||||||
|
for (groupOrPref in screen.root.preferencesList) {
|
||||||
|
traverseGroupOrPref(screenKey, groupOrPref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (preferences.isNotEmpty()) {
|
||||||
|
MetadataResult.Builder(MetadataResult.RESULT_OK)
|
||||||
|
.setMetadataList(
|
||||||
|
preferences.map {
|
||||||
|
it.preference.toMetadata(context, it.screenKey)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
} else {
|
||||||
|
MetadataResult.Builder(MetadataResult.RESULT_UNSUPPORTED).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Translate Framework GET VALUE request to Catalyst GET VALUE request */
|
/** Translate Framework GET VALUE request to Catalyst GET VALUE request */
|
||||||
fun transformFrameworkGetValueRequest(
|
fun transformFrameworkGetValueRequest(
|
||||||
request: GetValueRequest,
|
request: GetValueRequest,
|
||||||
@@ -133,6 +180,11 @@ fun transformCatalystSetValueResponse(@PreferenceSetterResult response: Int): Se
|
|||||||
return SetValueResult.Builder(resultCode).build()
|
return SetValueResult.Builder(resultCode).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class PreferenceWithScreen(
|
||||||
|
val screenKey: String,
|
||||||
|
val preference: PreferenceProto,
|
||||||
|
)
|
||||||
|
|
||||||
private fun PreferenceProto.toMetadata(
|
private fun PreferenceProto.toMetadata(
|
||||||
context: Context,
|
context: Context,
|
||||||
screenKey: String
|
screenKey: String
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.settings.service
|
package com.android.settings.service
|
||||||
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.platform.test.annotations.RequiresFlagsEnabled
|
import android.platform.test.annotations.RequiresFlagsEnabled
|
||||||
@@ -24,6 +23,7 @@ import android.platform.test.flag.junit.CheckFlagsRule
|
|||||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider
|
import android.platform.test.flag.junit.DeviceFlagsValueProvider
|
||||||
import android.service.settings.preferences.GetValueRequest
|
import android.service.settings.preferences.GetValueRequest
|
||||||
import android.service.settings.preferences.GetValueResult
|
import android.service.settings.preferences.GetValueResult
|
||||||
|
import android.service.settings.preferences.MetadataResult
|
||||||
import android.service.settings.preferences.SetValueRequest
|
import android.service.settings.preferences.SetValueRequest
|
||||||
import android.service.settings.preferences.SetValueResult
|
import android.service.settings.preferences.SetValueResult
|
||||||
import android.service.settings.preferences.SettingsPreferenceMetadata
|
import android.service.settings.preferences.SettingsPreferenceMetadata
|
||||||
@@ -37,9 +37,15 @@ import com.android.settingslib.graph.PreferenceGetterErrorCode
|
|||||||
import com.android.settingslib.graph.PreferenceGetterFlags
|
import com.android.settingslib.graph.PreferenceGetterFlags
|
||||||
import com.android.settingslib.graph.PreferenceGetterResponse
|
import com.android.settingslib.graph.PreferenceGetterResponse
|
||||||
import com.android.settingslib.graph.PreferenceSetterResult
|
import com.android.settingslib.graph.PreferenceSetterResult
|
||||||
|
import com.android.settingslib.graph.preferenceGroupProto
|
||||||
|
import com.android.settingslib.graph.preferenceOrGroupProto
|
||||||
|
import com.android.settingslib.graph.preferenceProto
|
||||||
|
import com.android.settingslib.graph.preferenceScreenProto
|
||||||
|
import com.android.settingslib.graph.proto.PreferenceGraphProto
|
||||||
import com.android.settingslib.graph.proto.PreferenceProto
|
import com.android.settingslib.graph.proto.PreferenceProto
|
||||||
import com.android.settingslib.graph.proto.PreferenceValueProto
|
import com.android.settingslib.graph.proto.PreferenceValueProto
|
||||||
import com.android.settingslib.graph.proto.TextProto
|
import com.android.settingslib.graph.proto.TextProto
|
||||||
|
import com.android.settingslib.graph.textProto
|
||||||
import com.android.settingslib.graph.toProto
|
import com.android.settingslib.graph.toProto
|
||||||
import com.android.settingslib.metadata.SensitivityLevel
|
import com.android.settingslib.metadata.SensitivityLevel
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
@@ -54,6 +60,73 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
@get:Rule
|
@get:Rule
|
||||||
val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transformCatalystGetMetadataResponse_emptyGraph_returnsFrameworkResponseWithError() {
|
||||||
|
val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
val graphProto = PreferenceGraphProto.newBuilder().build()
|
||||||
|
val fResult = transformCatalystGetMetadataResponse(context, graphProto)
|
||||||
|
with(fResult) {
|
||||||
|
assertThat(resultCode).isEqualTo(MetadataResult.RESULT_UNSUPPORTED)
|
||||||
|
assertThat(metadataList).isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun transformCatalystGetMetadataResponse_populatedGraph_returnsFrameworkResponseWithSuccess() {
|
||||||
|
val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
|
val screen = preferenceScreenProto {
|
||||||
|
root = preferenceGroupProto {
|
||||||
|
addAllPreferences(
|
||||||
|
listOf(
|
||||||
|
preferenceOrGroupProto {
|
||||||
|
group = preferenceGroupProto {
|
||||||
|
addPreferences(
|
||||||
|
preferenceOrGroupProto {
|
||||||
|
preference = preferenceProto {
|
||||||
|
key = "key1"
|
||||||
|
title = textProto { string = "title1" }
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
preferenceOrGroupProto {
|
||||||
|
preference = preferenceProto {
|
||||||
|
key = "key2"
|
||||||
|
title = textProto { string = "title2" }
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val graphProto = PreferenceGraphProto.newBuilder().putScreens("screen", screen).build()
|
||||||
|
|
||||||
|
val fResult = transformCatalystGetMetadataResponse(context, graphProto)
|
||||||
|
with(fResult) {
|
||||||
|
assertThat(resultCode).isEqualTo(MetadataResult.RESULT_OK)
|
||||||
|
assertThat(metadataList.size).isEqualTo(2)
|
||||||
|
}
|
||||||
|
assertThat(
|
||||||
|
fResult.metadataList.any {
|
||||||
|
it.key == "key1" &&
|
||||||
|
it.screenKey == "screen" &&
|
||||||
|
it.title == "title1" &&
|
||||||
|
it.isEnabled == true
|
||||||
|
}
|
||||||
|
).isTrue()
|
||||||
|
assertThat(
|
||||||
|
fResult.metadataList.any {
|
||||||
|
it.key == "key2" &&
|
||||||
|
it.screenKey == "screen" &&
|
||||||
|
it.title == "title2" &&
|
||||||
|
it.isEnabled == false
|
||||||
|
}
|
||||||
|
).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformFrameworkGetValueRequest_returnsValidCatalystRequest() {
|
fun transformFrameworkGetValueRequest_returnsValidCatalystRequest() {
|
||||||
val fRequest = GetValueRequest.Builder("screen", "pref").build()
|
val fRequest = GetValueRequest.Builder("screen", "pref").build()
|
||||||
|
Reference in New Issue
Block a user