1 /*
2  * Copyright (C) 2023 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 package com.android.systemui.util.settings
17 
18 import android.annotation.UserIdInt
19 import android.database.ContentObserver
20 import android.net.Uri
21 import android.os.UserHandle
22 import android.provider.Settings.SettingNotFoundException
23 import com.android.app.tracing.TraceUtils.trace
24 import com.android.systemui.settings.UserTracker
25 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
26 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
27 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
28 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault
29 
30 /**
31  * Used to interact with per-user Settings.Secure and Settings.System settings (but not
32  * Settings.Global, since those do not vary per-user)
33  *
34  * This interface can be implemented to give instance method (instead of static method) versions of
35  * Settings.Secure and Settings.System. It can be injected into class constructors and then faked or
36  * mocked as needed in tests.
37  *
38  * You can ask for [SecureSettings] or [SystemSettings] to be injected as needed.
39  *
40  * This class also provides [.registerContentObserver] methods, normally found on [ContentResolver]
41  * instances, unifying setting related actions in one place.
42  */
43 interface UserSettingsProxy : SettingsProxy {
44     /** Returns that [UserTracker] this instance was constructed with. */
45     val userTracker: UserTracker
46     /** Returns the user id for the associated [ContentResolver]. */
47     var userId: Int
48         get() = getContentResolver().userId
49         set(_) {
50             throw UnsupportedOperationException(
51                 "userId cannot be set in interface, use setter from an implementation instead."
52             )
53         }
54 
55     /**
56      * Returns the actual current user handle when querying with the current user. Otherwise,
57      * returns the passed in user id.
58      */
getRealUserHandlenull59     fun getRealUserHandle(userHandle: Int): Int {
60         return if (userHandle != UserHandle.USER_CURRENT) {
61             userHandle
62         } else userTracker.userId
63     }
64 
registerContentObserverSyncnull65     override fun registerContentObserverSync(uri: Uri, settingsObserver: ContentObserver) {
66         registerContentObserverForUserSync(uri, settingsObserver, userId)
67     }
68 
69     /** Convenience wrapper around [ContentResolver.registerContentObserver].' */
registerContentObserverSyncnull70     override fun registerContentObserverSync(
71         uri: Uri,
72         notifyForDescendants: Boolean,
73         settingsObserver: ContentObserver
74     ) {
75         registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
76     }
77 
78     /**
79      * Convenience wrapper around [ContentResolver.registerContentObserver]
80      *
81      * Implicitly calls [getUriFor] on the passed in name.
82      */
registerContentObserverForUserSyncnull83     fun registerContentObserverForUserSync(
84         name: String,
85         settingsObserver: ContentObserver,
86         userHandle: Int
87     ) {
88         registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
89     }
90 
91     /** Convenience wrapper around [ContentResolver.registerContentObserver] */
registerContentObserverForUserSyncnull92     fun registerContentObserverForUserSync(
93         uri: Uri,
94         settingsObserver: ContentObserver,
95         userHandle: Int
96     ) {
97         registerContentObserverForUserSync(uri, false, settingsObserver, userHandle)
98     }
99 
100     /**
101      * Convenience wrapper around [ContentResolver.registerContentObserver]
102      *
103      * Implicitly calls [getUriFor] on the passed in name.
104      */
registerContentObserverForUserSyncnull105     fun registerContentObserverForUserSync(
106         name: String,
107         notifyForDescendants: Boolean,
108         settingsObserver: ContentObserver,
109         userHandle: Int
110     ) {
111         registerContentObserverForUserSync(
112             getUriFor(name),
113             notifyForDescendants,
114             settingsObserver,
115             userHandle
116         )
117     }
118 
119     /** Convenience wrapper around [ContentResolver.registerContentObserver] */
registerContentObserverForUserSyncnull120     fun registerContentObserverForUserSync(
121         uri: Uri,
122         notifyForDescendants: Boolean,
123         settingsObserver: ContentObserver,
124         userHandle: Int
125     ) {
126         trace({ "USP#registerObserver#[$uri]" }) {
127             getContentResolver()
128                 .registerContentObserver(
129                     uri,
130                     notifyForDescendants,
131                     settingsObserver,
132                     getRealUserHandle(userHandle)
133                 )
134             Unit
135         }
136     }
137 
138     /**
139      * Look up a name in the database.
140      *
141      * @param name to look up in the table
142      * @return the corresponding value, or null if not present
143      */
getStringnull144     override fun getString(name: String): String {
145         return getStringForUser(name, userId)
146     }
147 
148     /** See [getString]. */
getStringForUsernull149     fun getStringForUser(name: String, userHandle: Int): String
150 
151     /**
152      * Store a name/value pair into the database. Values written by this method will be overridden
153      * if a restore happens in the future.
154      *
155      * @param name to store
156      * @param value to associate with the name
157      * @return true if the value was set, false on database errors
158      */
159     fun putString(name: String, value: String, overrideableByRestore: Boolean): Boolean
160 
161     override fun putString(name: String, value: String): Boolean {
162         return putStringForUser(name, value, userId)
163     }
164 
165     /** Similar implementation to [putString] for the specified [userHandle]. */
putStringForUsernull166     fun putStringForUser(name: String, value: String, userHandle: Int): Boolean
167 
168     /** Similar implementation to [putString] for the specified [userHandle]. */
169     fun putStringForUser(
170         name: String,
171         value: String,
172         tag: String?,
173         makeDefault: Boolean,
174         @UserIdInt userHandle: Int,
175         overrideableByRestore: Boolean
176     ): Boolean
177 
178     override fun getInt(name: String, def: Int): Int {
179         return getIntForUser(name, def, userId)
180     }
181 
182     /** Similar implementation to [getInt] for the specified [userHandle]. */
getIntForUsernull183     fun getIntForUser(name: String, def: Int, userHandle: Int): Int {
184         val v = getStringForUser(name, userHandle)
185         return try {
186             v.toInt()
187         } catch (e: NumberFormatException) {
188             def
189         }
190     }
191 
192     @Throws(SettingNotFoundException::class)
getIntnull193     override fun getInt(name: String) = getIntForUser(name, userId)
194 
195     /** Similar implementation to [getInt] for the specified [userHandle]. */
196     @Throws(SettingNotFoundException::class)
197     fun getIntForUser(name: String, userHandle: Int): Int {
198         val v = getStringForUser(name, userHandle)
199         return try {
200             v.toInt()
201         } catch (e: NumberFormatException) {
202             throw SettingNotFoundException(name)
203         }
204     }
205 
putIntnull206     override fun putInt(name: String, value: Int) = putIntForUser(name, value, userId)
207 
208     /** Similar implementation to [getInt] for the specified [userHandle]. */
209     fun putIntForUser(name: String, value: Int, userHandle: Int) =
210         putStringForUser(name, value.toString(), userHandle)
211 
212     override fun getBool(name: String, def: Boolean) = getBoolForUser(name, def, userId)
213 
214     /** Similar implementation to [getBool] for the specified [userHandle]. */
215     fun getBoolForUser(name: String, def: Boolean, userHandle: Int) =
216         getIntForUser(name, if (def) 1 else 0, userHandle) != 0
217 
218     @Throws(SettingNotFoundException::class)
219     override fun getBool(name: String) = getBoolForUser(name, userId)
220 
221     /** Similar implementation to [getBool] for the specified [userHandle]. */
222     @Throws(SettingNotFoundException::class)
223     fun getBoolForUser(name: String, userHandle: Int): Boolean {
224         return getIntForUser(name, userHandle) != 0
225     }
226 
putBoolnull227     override fun putBool(name: String, value: Boolean): Boolean {
228         return putBoolForUser(name, value, userId)
229     }
230 
231     /** Similar implementation to [putBool] for the specified [userHandle]. */
putBoolForUsernull232     fun putBoolForUser(name: String, value: Boolean, userHandle: Int) =
233         putIntForUser(name, if (value) 1 else 0, userHandle)
234 
235     /** Similar implementation to [getLong] for the specified [userHandle]. */
236     fun getLongForUser(name: String, def: Long, userHandle: Int): Long {
237         val valString = getStringForUser(name, userHandle)
238         return parseLongOrUseDefault(valString, def)
239     }
240 
241     /** Similar implementation to [getLong] for the specified [userHandle]. */
242     @Throws(SettingNotFoundException::class)
getLongForUsernull243     fun getLongForUser(name: String, userHandle: Int): Long {
244         val valString = getStringForUser(name, userHandle)
245         return parseLongOrThrow(name, valString)
246     }
247 
248     /** Similar implementation to [putLong] for the specified [userHandle]. */
putLongForUsernull249     fun putLongForUser(name: String, value: Long, userHandle: Int) =
250         putStringForUser(name, value.toString(), userHandle)
251 
252     /** Similar implementation to [getFloat] for the specified [userHandle]. */
253     fun getFloatForUser(name: String, def: Float, userHandle: Int): Float {
254         val v = getStringForUser(name, userHandle)
255         return parseFloat(v, def)
256     }
257 
258     /** Similar implementation to [getFloat] for the specified [userHandle]. */
259     @Throws(SettingNotFoundException::class)
getFloatForUsernull260     fun getFloatForUser(name: String, userHandle: Int): Float {
261         val v = getStringForUser(name, userHandle)
262         return parseFloatOrThrow(name, v)
263     }
264 
265     /** Similar implementation to [putFloat] for the specified [userHandle]. */
putFloatForUsernull266     fun putFloatForUser(name: String, value: Float, userHandle: Int) =
267         putStringForUser(name, value.toString(), userHandle)
268 }
269