1 /*
2  * Copyright (C) 2020 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.systemui.util.settings;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.content.ContentResolver;
23 import android.database.ContentObserver;
24 import android.net.Uri;
25 import android.os.UserHandle;
26 import android.provider.Settings;
27 
28 import com.android.systemui.settings.UserTracker;
29 
30 /**
31  * Used to interact with Settings.Secure, Settings.Global, and Settings.System.
32  *
33  * This interface can be implemented to give instance method (instead of static method) versions
34  * of Settings.Secure, Settings.Global, and Settings.System. It can be injected into class
35  * constructors and then faked or mocked as needed in tests.
36  *
37  * You can ask for {@link SecureSettings}, {@link GlobalSettings}, or {@link SystemSettings} to be
38  * injected as needed.
39  *
40  * This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
41  * normally found on {@link ContentResolver} instances, unifying setting related actions in one
42  * place.
43  */
44 public interface SettingsProxy {
45 
46     /**
47      * Returns the {@link ContentResolver} this instance was constructed with.
48      */
getContentResolver()49     ContentResolver getContentResolver();
50 
51     /**
52      * Returns that {@link UserTracker} this instance was constructed with.
53      */
getUserTracker()54     UserTracker getUserTracker();
55 
56     /**
57      * Returns the user id for the associated {@link ContentResolver}.
58      */
getUserId()59     default int getUserId() {
60         return getContentResolver().getUserId();
61     }
62 
63     /**
64      * Returns the actual current user handle when querying with the current user. Otherwise,
65      * returns the passed in user id.
66      */
getRealUserHandle(int userHandle)67     default int getRealUserHandle(int userHandle) {
68         if (userHandle != UserHandle.USER_CURRENT) {
69             return userHandle;
70         }
71         return getUserTracker().getUserId();
72     }
73 
74     /**
75      * Construct the content URI for a particular name/value pair,
76      * useful for monitoring changes with a ContentObserver.
77      * @param name to look up in the table
78      * @return the corresponding content URI, or null if not present
79      */
getUriFor(String name)80     Uri getUriFor(String name);
81 
82     /**
83      * Convenience wrapper around
84      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
85      *
86      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
87      */
registerContentObserver(String name, ContentObserver settingsObserver)88     default void registerContentObserver(String name, ContentObserver settingsObserver) {
89         registerContentObserver(getUriFor(name), settingsObserver);
90     }
91 
92     /**
93      * Convenience wrapper around
94      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
95      */
registerContentObserver(Uri uri, ContentObserver settingsObserver)96     default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
97         registerContentObserverForUser(uri, settingsObserver, getUserId());
98     }
99 
100     /**
101      * Convenience wrapper around
102      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
103      *
104      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
105      */
registerContentObserver(String name, boolean notifyForDescendants, ContentObserver settingsObserver)106     default void registerContentObserver(String name, boolean notifyForDescendants,
107             ContentObserver settingsObserver) {
108         registerContentObserver(getUriFor(name), notifyForDescendants, settingsObserver);
109     }
110 
111     /**
112      * Convenience wrapper around
113      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
114      */
registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver)115     default void registerContentObserver(Uri uri, boolean notifyForDescendants,
116             ContentObserver settingsObserver) {
117         registerContentObserverForUser(uri, notifyForDescendants, settingsObserver, getUserId());
118     }
119 
120     /**
121      * Convenience wrapper around
122      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
123      *
124      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
125      */
registerContentObserverForUser( String name, ContentObserver settingsObserver, int userHandle)126     default void registerContentObserverForUser(
127             String name, ContentObserver settingsObserver, int userHandle) {
128         registerContentObserverForUser(
129                 getUriFor(name), settingsObserver, userHandle);
130     }
131 
132     /**
133      * Convenience wrapper around
134      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
135      */
registerContentObserverForUser( Uri uri, ContentObserver settingsObserver, int userHandle)136     default void registerContentObserverForUser(
137             Uri uri, ContentObserver settingsObserver, int userHandle) {
138         registerContentObserverForUser(
139                 uri, false, settingsObserver, userHandle);
140     }
141 
142     /**
143      * Convenience wrapper around
144      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
145      *
146      * Implicitly calls {@link #getUriFor(String)} on the passed in name.
147      */
registerContentObserverForUser( String name, boolean notifyForDescendants, ContentObserver settingsObserver, int userHandle)148     default void registerContentObserverForUser(
149             String name, boolean notifyForDescendants, ContentObserver settingsObserver,
150             int userHandle) {
151         registerContentObserverForUser(
152                 getUriFor(name), notifyForDescendants, settingsObserver, userHandle);
153     }
154 
155     /**
156      * Convenience wrapper around
157      * {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
158      */
registerContentObserverForUser( Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver, int userHandle)159     default void registerContentObserverForUser(
160             Uri uri, boolean notifyForDescendants, ContentObserver settingsObserver,
161             int userHandle) {
162         getContentResolver().registerContentObserver(
163                 uri, notifyForDescendants, settingsObserver, getRealUserHandle(userHandle));
164     }
165 
166     /** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
unregisterContentObserver(ContentObserver settingsObserver)167     default void unregisterContentObserver(ContentObserver settingsObserver) {
168         getContentResolver().unregisterContentObserver(settingsObserver);
169     }
170 
171     /**
172      * Look up a name in the database.
173      * @param name to look up in the table
174      * @return the corresponding value, or null if not present
175      */
getString(String name)176     default String getString(String name) {
177         return getStringForUser(name, getUserId());
178     }
179 
180     /**See {@link #getString(String)}. */
getStringForUser(String name, int userHandle)181     String getStringForUser(String name, int userHandle);
182 
183     /**
184      * Store a name/value pair into the database. Values written by this method will be
185      * overridden if a restore happens in the future.
186      *
187      * @param name to store
188      * @param value to associate with the name
189      * @return true if the value was set, false on database errors
190      */
putString(String name, String value, boolean overrideableByRestore)191     boolean putString(String name, String value, boolean overrideableByRestore);
192 
193     /**
194      * Store a name/value pair into the database.
195      * @param name to store
196      * @param value to associate with the name
197      * @return true if the value was set, false on database errors
198      */
putString(String name, String value)199     default boolean putString(String name, String value) {
200         return putStringForUser(name, value, getUserId());
201     }
202 
203     /** See {@link #putString(String, String)}. */
putStringForUser(String name, String value, int userHandle)204     boolean putStringForUser(String name, String value, int userHandle);
205 
206     /** See {@link #putString(String, String)}. */
putStringForUser(@onNull String name, @Nullable String value, @Nullable String tag, boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore)207     boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag,
208             boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore);
209 
210     /**
211      * Store a name/value pair into the database.
212      * <p>
213      * The method takes an optional tag to associate with the setting
214      * which can be used to clear only settings made by your package and
215      * associated with this tag by passing the tag to {@link
216      * #resetToDefaults(String)}. Anyone can override
217      * the current tag. Also if another package changes the setting
218      * then the tag will be set to the one specified in the set call
219      * which can be null. Also any of the settings setters that do not
220      * take a tag as an argument effectively clears the tag.
221      * </p><p>
222      * For example, if you set settings A and B with tags T1 and T2 and
223      * another app changes setting A (potentially to the same value), it
224      * can assign to it a tag T3 (note that now the package that changed
225      * the setting is not yours). Now if you reset your changes for T1 and
226      * T2 only setting B will be reset and A not (as it was changed by
227      * another package) but since A did not change you are in the desired
228      * initial state. Now if the other app changes the value of A (assuming
229      * you registered an observer in the beginning) you would detect that
230      * the setting was changed by another app and handle this appropriately
231      * (ignore, set back to some value, etc).
232      * </p><p>
233      * Also the method takes an argument whether to make the value the
234      * default for this setting. If the system already specified a default
235      * value, then the one passed in here will <strong>not</strong>
236      * be set as the default.
237      * </p>
238      *
239      * @param name to store.
240      * @param value to associate with the name.
241      * @param tag to associate with the setting.
242      * @param makeDefault whether to make the value the default one.
243      * @return true if the value was set, false on database errors.
244      *
245      * @see #resetToDefaults(String)
246      *
247      */
putString(@onNull String name, @Nullable String value, @Nullable String tag, boolean makeDefault)248     boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag,
249             boolean makeDefault);
250 
251     /**
252      * Convenience function for retrieving a single secure settings value
253      * as an integer.  Note that internally setting values are always
254      * stored as strings; this function converts the string to an integer
255      * for you.  The default value will be returned if the setting is
256      * not defined or not an integer.
257      *
258      * @param name The name of the setting to retrieve.
259      * @param def Value to return if the setting is not defined.
260      *
261      * @return The setting's current value, or 'def' if it is not defined
262      * or not a valid integer.
263      */
getInt(String name, int def)264     default int getInt(String name, int def) {
265         return getIntForUser(name, def, getUserId());
266     }
267 
268     /** See {@link #getInt(String, int)}. */
getIntForUser(String name, int def, int userHandle)269     default int getIntForUser(String name, int def, int userHandle) {
270         String v = getStringForUser(name, userHandle);
271         try {
272             return v != null ? Integer.parseInt(v) : def;
273         } catch (NumberFormatException e) {
274             return def;
275         }
276     }
277 
278     /**
279      * Convenience function for retrieving a single secure settings value
280      * as an integer.  Note that internally setting values are always
281      * stored as strings; this function converts the string to an integer
282      * for you.
283      * <p>
284      * This version does not take a default value.  If the setting has not
285      * been set, or the string value is not a number,
286      * it throws {@link Settings.SettingNotFoundException}.
287      *
288      * @param name The name of the setting to retrieve.
289      *
290      * @throws Settings.SettingNotFoundException Thrown if a setting by the given
291      * name can't be found or the setting value is not an integer.
292      *
293      * @return The setting's current value.
294      */
getInt(String name)295     default int getInt(String name) throws Settings.SettingNotFoundException {
296         return getIntForUser(name, getUserId());
297     }
298 
299     /** See {@link #getInt(String)}. */
getIntForUser(String name, int userHandle)300     default int getIntForUser(String name, int userHandle)
301             throws Settings.SettingNotFoundException {
302         String v = getStringForUser(name, userHandle);
303         try {
304             return Integer.parseInt(v);
305         } catch (NumberFormatException e) {
306             throw new Settings.SettingNotFoundException(name);
307         }
308     }
309 
310     /**
311      * Convenience function for updating a single settings value as an
312      * integer. This will either create a new entry in the table if the
313      * given name does not exist, or modify the value of the existing row
314      * with that name.  Note that internally setting values are always
315      * stored as strings, so this function converts the given value to a
316      * string before storing it.
317      *
318      * @param name The name of the setting to modify.
319      * @param value The new value for the setting.
320      * @return true if the value was set, false on database errors
321      */
putInt(String name, int value)322     default boolean putInt(String name, int value) {
323         return putIntForUser(name, value, getUserId());
324     }
325 
326     /** See {@link #putInt(String, int)}. */
putIntForUser(String name, int value, int userHandle)327     default boolean putIntForUser(String name, int value, int userHandle) {
328         return putStringForUser(name, Integer.toString(value), userHandle);
329     }
330 
331     /**
332      * Convenience function for retrieving a single secure settings value
333      * as a boolean.  Note that internally setting values are always
334      * stored as strings; this function converts the string to a boolean
335      * for you.  The default value will be returned if the setting is
336      * not defined or not a boolean.
337      *
338      * @param name The name of the setting to retrieve.
339      * @param def Value to return if the setting is not defined.
340      *
341      * @return The setting's current value, or 'def' if it is not defined
342      * or not a valid boolean.
343      */
getBool(String name, boolean def)344     default boolean getBool(String name, boolean def) {
345         return getBoolForUser(name, def, getUserId());
346     }
347 
348     /** See {@link #getBool(String, boolean)}. */
getBoolForUser(String name, boolean def, int userHandle)349     default boolean getBoolForUser(String name, boolean def, int userHandle) {
350         return getIntForUser(name, def ? 1 : 0, userHandle) != 0;
351     }
352 
353     /**
354      * Convenience function for retrieving a single secure settings value
355      * as a boolean.  Note that internally setting values are always
356      * stored as strings; this function converts the string to a boolean
357      * for you.
358      * <p>
359      * This version does not take a default value.  If the setting has not
360      * been set, or the string value is not a number,
361      * it throws {@link Settings.SettingNotFoundException}.
362      *
363      * @param name The name of the setting to retrieve.
364      *
365      * @throws Settings.SettingNotFoundException Thrown if a setting by the given
366      * name can't be found or the setting value is not a boolean.
367      *
368      * @return The setting's current value.
369      */
getBool(String name)370     default boolean getBool(String name) throws Settings.SettingNotFoundException {
371         return getBoolForUser(name, getUserId());
372     }
373 
374     /** See {@link #getBool(String)}. */
getBoolForUser(String name, int userHandle)375     default boolean getBoolForUser(String name, int userHandle)
376             throws Settings.SettingNotFoundException {
377         return getIntForUser(name, userHandle) != 0;
378     }
379 
380     /**
381      * Convenience function for updating a single settings value as a
382      * boolean. This will either create a new entry in the table if the
383      * given name does not exist, or modify the value of the existing row
384      * with that name.  Note that internally setting values are always
385      * stored as strings, so this function converts the given value to a
386      * string before storing it.
387      *
388      * @param name The name of the setting to modify.
389      * @param value The new value for the setting.
390      * @return true if the value was set, false on database errors
391      */
putBool(String name, boolean value)392     default boolean putBool(String name, boolean value) {
393         return putBoolForUser(name, value, getUserId());
394     }
395 
396     /** See {@link #putBool(String, boolean)}. */
putBoolForUser(String name, boolean value, int userHandle)397     default boolean putBoolForUser(String name, boolean value, int userHandle) {
398         return putIntForUser(name, value ? 1 : 0, userHandle);
399     }
400 
401     /**
402      * Convenience function for retrieving a single secure settings value
403      * as a {@code long}.  Note that internally setting values are always
404      * stored as strings; this function converts the string to a {@code long}
405      * for you.  The default value will be returned if the setting is
406      * not defined or not a {@code long}.
407      *
408      * @param name The name of the setting to retrieve.
409      * @param def Value to return if the setting is not defined.
410      *
411      * @return The setting's current value, or 'def' if it is not defined
412      * or not a valid {@code long}.
413      */
getLong(String name, long def)414     default long getLong(String name, long def) {
415         return getLongForUser(name, def, getUserId());
416     }
417 
418     /** See {@link #getLong(String, long)}. */
getLongForUser(String name, long def, int userHandle)419     default long getLongForUser(String name, long def, int userHandle) {
420         String valString = getStringForUser(name, userHandle);
421         long value;
422         try {
423             value = valString != null ? Long.parseLong(valString) : def;
424         } catch (NumberFormatException e) {
425             value = def;
426         }
427         return value;
428     }
429 
430     /**
431      * Convenience function for retrieving a single secure settings value
432      * as a {@code long}.  Note that internally setting values are always
433      * stored as strings; this function converts the string to a {@code long}
434      * for you.
435      * <p>
436      * This version does not take a default value.  If the setting has not
437      * been set, or the string value is not a number,
438      * it throws {@link Settings.SettingNotFoundException}.
439      *
440      * @param name The name of the setting to retrieve.
441      *
442      * @return The setting's current value.
443      * @throws Settings.SettingNotFoundException Thrown if a setting by the given
444      * name can't be found or the setting value is not an integer.
445      */
getLong(String name)446     default long getLong(String name) throws Settings.SettingNotFoundException {
447         return getLongForUser(name, getUserId());
448     }
449 
450     /** See {@link #getLong(String)}. */
getLongForUser(String name, int userHandle)451     default long getLongForUser(String name, int userHandle)
452             throws Settings.SettingNotFoundException {
453         String valString = getStringForUser(name, userHandle);
454         try {
455             return Long.parseLong(valString);
456         } catch (NumberFormatException e) {
457             throw new Settings.SettingNotFoundException(name);
458         }
459     }
460 
461     /**
462      * Convenience function for updating a secure settings value as a long
463      * integer. This will either create a new entry in the table if the
464      * given name does not exist, or modify the value of the existing row
465      * with that name.  Note that internally setting values are always
466      * stored as strings, so this function converts the given value to a
467      * string before storing it.
468      *
469      * @param name The name of the setting to modify.
470      * @param value The new value for the setting.
471      * @return true if the value was set, false on database errors
472      */
putLong(String name, long value)473     default boolean putLong(String name, long value) {
474         return putLongForUser(name, value, getUserId());
475     }
476 
477     /** See {@link #putLong(String, long)}. */
putLongForUser(String name, long value, int userHandle)478     default boolean putLongForUser(String name, long value, int userHandle) {
479         return putStringForUser(name, Long.toString(value), userHandle);
480     }
481 
482     /**
483      * Convenience function for retrieving a single secure settings value
484      * as a floating point number.  Note that internally setting values are
485      * always stored as strings; this function converts the string to an
486      * float for you. The default value will be returned if the setting
487      * is not defined or not a valid float.
488      *
489      * @param name The name of the setting to retrieve.
490      * @param def Value to return if the setting is not defined.
491      *
492      * @return The setting's current value, or 'def' if it is not defined
493      * or not a valid float.
494      */
getFloat(String name, float def)495     default float getFloat(String name, float def) {
496         return getFloatForUser(name, def, getUserId());
497     }
498 
499     /** See {@link #getFloat(String)}. */
getFloatForUser(String name, float def, int userHandle)500     default float getFloatForUser(String name, float def, int userHandle) {
501         String v = getStringForUser(name, userHandle);
502         try {
503             return v != null ? Float.parseFloat(v) : def;
504         } catch (NumberFormatException e) {
505             return def;
506         }
507     }
508 
509     /**
510      * Convenience function for retrieving a single secure settings value
511      * as a float.  Note that internally setting values are always
512      * stored as strings; this function converts the string to a float
513      * for you.
514      * <p>
515      * This version does not take a default value.  If the setting has not
516      * been set, or the string value is not a number,
517      * it throws {@link Settings.SettingNotFoundException}.
518      *
519      * @param name The name of the setting to retrieve.
520      *
521      * @throws Settings.SettingNotFoundException Thrown if a setting by the given
522      * name can't be found or the setting value is not a float.
523      *
524      * @return The setting's current value.
525      */
getFloat(String name)526     default float getFloat(String name) throws Settings.SettingNotFoundException {
527         return getFloatForUser(name, getUserId());
528     }
529 
530     /** See {@link #getFloat(String, float)}. */
getFloatForUser(String name, int userHandle)531     default float getFloatForUser(String name, int userHandle)
532             throws Settings.SettingNotFoundException {
533         String v = getStringForUser(name, userHandle);
534         if (v == null) {
535             throw new Settings.SettingNotFoundException(name);
536         }
537         try {
538             return Float.parseFloat(v);
539         } catch (NumberFormatException e) {
540             throw new Settings.SettingNotFoundException(name);
541         }
542     }
543 
544     /**
545      * Convenience function for updating a single settings value as a
546      * floating point number. This will either create a new entry in the
547      * table if the given name does not exist, or modify the value of the
548      * existing row with that name.  Note that internally setting values
549      * are always stored as strings, so this function converts the given
550      * value to a string before storing it.
551      *
552      * @param name The name of the setting to modify.
553      * @param value The new value for the setting.
554      * @return true if the value was set, false on database errors
555      */
putFloat(String name, float value)556     default boolean putFloat(String name, float value) {
557         return putFloatForUser(name, value, getUserId());
558     }
559 
560     /** See {@link #putFloat(String, float)} */
putFloatForUser(String name, float value, int userHandle)561     default boolean putFloatForUser(String name, float value, int userHandle) {
562         return putStringForUser(name, Float.toString(value), userHandle);
563     }
564 }
565