• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settingslib.graph
18 
19 import android.app.Application
20 import android.os.Bundle
21 import android.os.Parcelable
22 import android.os.SystemClock
23 import com.android.settingslib.graph.proto.PreferenceGraphProto
24 import com.android.settingslib.ipc.ApiHandler
25 import com.android.settingslib.ipc.ApiPermissionChecker
26 import com.android.settingslib.ipc.MessageCodec
27 import com.android.settingslib.metadata.PreferenceRemoteOpMetricsLogger
28 import com.android.settingslib.metadata.PreferenceScreenCoordinate
29 import com.android.settingslib.metadata.PreferenceScreenRegistry
30 import com.android.settingslib.preference.PreferenceScreenProvider
31 import java.util.Locale
32 
33 /** API to get preference graph. */
34 class GetPreferenceGraphApiHandler(
35     override val id: Int,
36     private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>,
37     private val metricsLogger: PreferenceRemoteOpMetricsLogger? = null,
38     private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> = emptySet(),
39 ) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> {
40 
41     override val requestCodec: MessageCodec<GetPreferenceGraphRequest>
42         get() = GetPreferenceGraphRequestCodec
43 
44     override val responseCodec: MessageCodec<PreferenceGraphProto>
45         get() = PreferenceGraphProtoCodec
46 
47     override fun hasPermission(
48         application: Application,
49         callingPid: Int,
50         callingUid: Int,
51         request: GetPreferenceGraphRequest,
52     ) = permissionChecker.hasPermission(application, callingPid, callingUid, request)
53 
54     override suspend fun invoke(
55         application: Application,
56         callingPid: Int,
57         callingUid: Int,
58         request: GetPreferenceGraphRequest,
59     ): PreferenceGraphProto {
60         val elapsedRealtime = SystemClock.elapsedRealtime()
61         var success = false
62         try {
63             val builder = PreferenceGraphBuilder.of(application, callingPid, callingUid, request)
64             if (request.screens.isEmpty()) {
65                 val factories = PreferenceScreenRegistry.preferenceScreenMetadataFactories
66                 factories.forEachAsync { _, factory -> builder.addPreferenceScreen(factory) }
67                 for (provider in preferenceScreenProviders) {
68                     builder.addPreferenceScreenProvider(provider)
69                 }
70             }
71             val result = builder.build()
72             success = true
73             return result
74         } finally {
75             metricsLogger?.logGraphApi(
76                 application,
77                 callingUid,
78                 success,
79                 SystemClock.elapsedRealtime() - elapsedRealtime,
80             )
81         }
82     }
83 }
84 
85 /**
86  * Request of [GetPreferenceGraphApiHandler].
87  *
88  * @param screens screens of the preference graph
89  * @param visitedScreens visited preference screens
90  * @param locale locale of the preference graph
91  */
92 data class GetPreferenceGraphRequest
93 @JvmOverloads
94 constructor(
95     val screens: Set<PreferenceScreenCoordinate> = setOf(),
96     val visitedScreens: Set<PreferenceScreenCoordinate> = setOf(),
97     val locale: Locale? = null,
98     val flags: Int = PreferenceGetterFlags.ALL,
99     val includeValueDescriptor: Boolean = true,
100 )
101 
102 object GetPreferenceGraphRequestCodec : MessageCodec<GetPreferenceGraphRequest> {
encodenull103     override fun encode(data: GetPreferenceGraphRequest): Bundle =
104         Bundle(4).apply {
105             putParcelableArray(KEY_SCREENS, data.screens.toTypedArray())
106             putParcelableArray(KEY_VISITED_SCREENS, data.visitedScreens.toTypedArray())
107             putString(KEY_LOCALE, data.locale?.toLanguageTag())
108             putInt(KEY_FLAGS, data.flags)
109         }
110 
111     @Suppress("DEPRECATION")
decodenull112     override fun decode(data: Bundle): GetPreferenceGraphRequest {
113         data.classLoader = PreferenceScreenCoordinate::class.java.classLoader
114         val screens = data.getParcelableArray(KEY_SCREENS) ?: arrayOf()
115         val visitedScreens = data.getParcelableArray(KEY_VISITED_SCREENS) ?: arrayOf()
116         fun String?.toLocale() = if (this != null) Locale.forLanguageTag(this) else null
117         fun Array<Parcelable>.toScreenCoordinates() =
118             buildSet(size) {
119                 for (element in this@toScreenCoordinates) add(element as PreferenceScreenCoordinate)
120             }
121         return GetPreferenceGraphRequest(
122             screens.toScreenCoordinates(),
123             visitedScreens.toScreenCoordinates(),
124             data.getString(KEY_LOCALE).toLocale(),
125             data.getInt(KEY_FLAGS),
126         )
127     }
128 
129     private const val KEY_SCREENS = "s"
130     private const val KEY_VISITED_SCREENS = "v"
131     private const val KEY_LOCALE = "l"
132     private const val KEY_FLAGS = "f"
133 }
134 
135 object PreferenceGraphProtoCodec : MessageCodec<PreferenceGraphProto> {
encodenull136     override fun encode(data: PreferenceGraphProto): Bundle =
137         Bundle(1).apply { putByteArray(KEY_GRAPH, data.toByteArray()) }
138 
decodenull139     override fun decode(data: Bundle): PreferenceGraphProto =
140         PreferenceGraphProto.parseFrom(data.getByteArray(KEY_GRAPH)!!)
141 
142     private const val KEY_GRAPH = "g"
143 }
144