• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 android.provider;
18 
19 import static android.Manifest.permission.READ_DEVICE_CONFIG;
20 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
21 
22 import android.annotation.CallbackExecutor;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.RequiresPermission;
26 import android.annotation.SystemApi;
27 import android.annotation.TestApi;
28 import android.app.ActivityThread;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.database.ContentObserver;
33 import android.net.Uri;
34 import android.provider.Settings.Config.SyncDisabledMode;
35 import android.provider.Settings.ResetMode;
36 import android.util.ArrayMap;
37 import android.util.Log;
38 import android.util.Pair;
39 
40 import com.android.internal.annotations.GuardedBy;
41 import com.android.internal.util.Preconditions;
42 
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.concurrent.Executor;
50 
51 /**
52  * Device level configuration parameters which can be tuned by a separate configuration service.
53  * Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used
54  * by native code and should be pushed to system properties to make them accessible.
55  *
56  * @hide
57  */
58 @SystemApi
59 public final class DeviceConfig {
60     /**
61      * The content:// style URL for the config table.
62      *
63      * @hide
64      */
65     public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
66 
67     /**
68      * Namespace for activity manager related features. These features will be applied
69      * immediately upon change.
70      *
71      * @hide
72      */
73     @SystemApi
74     public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
75 
76     /**
77      * Namespace for activity manager, specific to the "component alias" feature. We needed a
78      * different namespace in order to avoid phonetype from resetting it.
79      * @hide
80      */
81     public static final String NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS = "activity_manager_ca";
82 
83     /**
84      * Namespace for all activity manager related features that are used at the native level.
85      * These features are applied at reboot.
86      *
87      * @hide
88      */
89     @SystemApi
90     public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT =
91             "activity_manager_native_boot";
92 
93     /**
94      * Namespace for AlarmManager configurations.
95      *
96      * @hide
97      */
98     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
99     @TestApi
100     public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
101 
102     /**
103      * Namespace for all app compat related features.  These features will be applied
104      * immediately upon change.
105      *
106      * @hide
107      */
108     @SystemApi
109     public static final String NAMESPACE_APP_COMPAT = "app_compat";
110 
111     /**
112      * Namespace for all app hibernation related features.
113      * @hide
114      */
115     @SystemApi
116     public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation";
117 
118     /**
119      * Namespace for all AppSearch related features.
120      * @hide
121      */
122     @SystemApi
123     public static final String NAMESPACE_APPSEARCH = "appsearch";
124 
125     /**
126      * Namespace for app standby configurations.
127      *
128      * @hide
129      */
130     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
131     public static final String NAMESPACE_APP_STANDBY = "app_standby";
132 
133     /**
134      * Namespace for AttentionManagerService related features.
135      *
136      * @hide
137      */
138     @SystemApi
139     public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
140 
141     /**
142      * Namespace for autofill feature that provides suggestions across all apps when
143      * the user interacts with input fields.
144      *
145      * @hide
146      */
147     @SystemApi
148     public static final String NAMESPACE_AUTOFILL = "autofill";
149 
150     /**
151      * Namespace for battery saver feature.
152      *
153      * @hide
154      */
155     @SystemApi
156     public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
157 
158     /**
159      * Namespace for blobstore feature that allows apps to share data blobs.
160      *
161      * @hide
162      */
163     @SystemApi
164     public static final String NAMESPACE_BLOBSTORE = "blobstore";
165 
166     /**
167      * Namespace for all Bluetooth related features.
168      *
169      * @hide
170      */
171     @SystemApi
172     public static final String NAMESPACE_BLUETOOTH = "bluetooth";
173 
174     /**
175      * Namespace for features relating to clipboard.
176      *
177      * @hide
178      */
179     @SystemApi
180     public static final String NAMESPACE_CLIPBOARD = "clipboard";
181 
182     /**
183      * Namespace for all networking connectivity related features.
184      *
185      * @hide
186      */
187     @SystemApi
188     public static final String NAMESPACE_CONNECTIVITY = "connectivity";
189 
190     /**
191      * Namespace for CaptivePortalLogin module.
192      *
193      * @hide
194      */
195     @SystemApi
196     public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login";
197 
198     /**
199      * Namespace for Tethering module.
200      *
201      * @hide
202      */
203     @SystemApi
204     public static final String NAMESPACE_TETHERING = "tethering";
205 
206     /**
207      * Namespace for content capture feature used by on-device machine intelligence
208      * to provide suggestions in a privacy-safe manner.
209      *
210      * @hide
211      */
212     @SystemApi
213     public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
214 
215     /**
216      * Namespace for device idle configurations.
217      *
218      * @hide
219      */
220     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
221     @TestApi
222     public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
223 
224     /**
225      * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
226      *
227      * @deprecated No longer used
228      * @hide
229      */
230     @Deprecated
231     @SystemApi
232     public static final String NAMESPACE_DEX_BOOT = "dex_boot";
233 
234     /**
235      * Namespace for display manager related features. The names to access the properties in this
236      * namespace should be defined in {@link android.hardware.display.DisplayManager}.
237      *
238      * @hide
239      */
240     @SystemApi
241     public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
242 
243     /**
244      * Namespace for all Game Driver features.
245      *
246      * @hide
247      */
248     @SystemApi
249     public static final String NAMESPACE_GAME_DRIVER = "game_driver";
250 
251     /**
252      * Namespace for all input-related features that are used at the native level.
253      * These features are applied at reboot.
254      *
255      * @hide
256      */
257     @SystemApi
258     public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
259 
260     /**
261      * Namespace for attention-based features provided by on-device machine intelligence.
262      *
263      * @hide
264      */
265     @SystemApi
266     public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
267 
268     /**
269      * Definitions for properties related to Content Suggestions.
270      *
271      * @hide
272      */
273     public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS =
274             "intelligence_content_suggestions";
275 
276     /**
277      * Namespace for JobScheduler configurations.
278      * @hide
279      */
280     @TestApi
281     public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
282 
283     /**
284      * Namespace for all lmkd related features.
285      *
286      * @hide
287      */
288     @SystemApi
289     public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
290 
291     /**
292      * Namespace for all location related features.
293      *
294      * @hide
295      */
296     @SystemApi
297     public static final String NAMESPACE_LOCATION = "location";
298 
299     /**
300      * Namespace for all media related features.
301      *
302      * @hide
303      */
304     @SystemApi
305     public static final String NAMESPACE_MEDIA = "media";
306 
307     /**
308      * Namespace for all media native related features.
309      *
310      * @hide
311      */
312     @SystemApi
313     public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
314 
315     /**
316      * Namespace for all Kernel Multi-Gen LRU feature.
317      *
318      * @hide
319      */
320     public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native";
321 
322     /**
323      * Namespace for all netd related features.
324      *
325      * @hide
326      */
327     @SystemApi
328     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
329 
330     /**
331      * Namespace for all Android NNAPI related features.
332      *
333      * @hide
334      */
335     @SystemApi
336     public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
337 
338     /**
339      * Namespace for all OnDevicePersonalization related feature.
340      * @hide
341      */
342     @SystemApi
343     public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization";
344 
345     /**
346      * Namespace for features related to the Package Manager Service.
347      *
348      * @hide
349      */
350     @SystemApi
351     public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
352 
353     /**
354      * Namespace for features related to the Profcollect native Service.
355      * These features are applied at reboot.
356      *
357      * @hide
358      */
359     @SystemApi
360     public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
361 
362     /**
363      * Namespace for features related to Reboot Readiness detection.
364      *
365      * @hide
366      */
367     @SystemApi
368     public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness";
369 
370     /**
371      * Namespace for Rollback flags that are applied immediately.
372      *
373      * @hide
374      */
375     @SystemApi
376     public static final String NAMESPACE_ROLLBACK = "rollback";
377 
378     /**
379      * Namespace for Rollback flags that are applied after a reboot.
380      *
381      * @hide
382      */
383     @SystemApi
384     public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
385 
386     /**
387      * Namespace for Rotation Resolver Manager Service.
388      *
389      * @hide
390      */
391     public static final String NAMESPACE_ROTATION_RESOLVER = "rotation_resolver";
392 
393     /**
394      * Namespace for all runtime related features that don't require a reboot to become active.
395      * There are no feature flags using NAMESPACE_RUNTIME.
396      *
397      * @hide
398      */
399     @SystemApi
400     public static final String NAMESPACE_RUNTIME = "runtime";
401 
402     /**
403      * Namespace for all runtime related features that require system properties for accessing
404      * the feature flags from C++ or Java language code. One example is the app image startup
405      * cache feature use_app_image_startup_cache.
406      *
407      * @hide
408      */
409     @SystemApi
410     public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
411 
412     /**
413      * Namespace for all runtime native boot related features. Boot in this case refers to the
414      * fact that the properties only take affect after rebooting the device.
415      *
416      * @hide
417      */
418     @SystemApi
419     public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
420 
421     /**
422      * Namespace for system scheduler related features. These features will be applied
423      * immediately upon change.
424      *
425      * @hide
426      */
427     @SystemApi
428     public static final String NAMESPACE_SCHEDULER = "scheduler";
429 
430     /**
431      * Namespace for all SdkSandbox related features.
432      * @hide
433      */
434     @SystemApi
435     public static final String NAMESPACE_SDK_SANDBOX = "sdk_sandbox";
436 
437     /**
438      * Namespace for settings statistics features.
439      *
440      * @hide
441      */
442     public static final String NAMESPACE_SETTINGS_STATS = "settings_stats";
443 
444     /**
445      * Namespace for all statsd java features that can be applied immediately.
446      *
447      * @hide
448      */
449     @SystemApi
450     public static final String NAMESPACE_STATSD_JAVA = "statsd_java";
451 
452     /**
453      * Namespace for all statsd java features that are applied on boot.
454      *
455      * @hide
456      */
457     @SystemApi
458     public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot";
459 
460     /**
461      * Namespace for all statsd native features that can be applied immediately.
462      *
463      * @hide
464      */
465     @SystemApi
466     public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
467 
468     /**
469      * Namespace for all statsd native features that are applied on boot.
470      *
471      * @hide
472      */
473     @SystemApi
474     public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
475 
476     /**
477      * Namespace for storage-related features.
478      *
479      * @deprecated Replace storage namespace with storage_native_boot.
480      * @hide
481      */
482     @Deprecated
483     @SystemApi
484     public static final String NAMESPACE_STORAGE = "storage";
485 
486     /**
487      * Namespace for storage-related features, including native and boot.
488      *
489      * @hide
490      */
491     @SystemApi
492     public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
493 
494     /**
495      * Namespace for all AdServices related features.
496      * @hide
497      */
498     @SystemApi
499     public static final String NAMESPACE_ADSERVICES = "adservices";
500 
501     /**
502      * Namespace for all SurfaceFlinger features that are used at the native level.
503      * These features are applied on boot or after reboot.
504      *
505      * @hide
506      */
507     @SystemApi
508     public static final String NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT =
509             "surface_flinger_native_boot";
510 
511     /**
512      * Namespace for swcodec native related features.
513      *
514      * @hide
515      */
516     @SystemApi
517     public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native";
518 
519 
520     /**
521      * Namespace for System UI related features.
522      *
523      * @hide
524      */
525     @SystemApi
526     public static final String NAMESPACE_SYSTEMUI = "systemui";
527 
528     /**
529      * Namespace for system time and time zone detection related features / behavior.
530      *
531      * @hide
532      */
533     @SystemApi
534     public static final String NAMESPACE_SYSTEM_TIME = "system_time";
535 
536     /**
537      * Namespace for TARE configurations.
538      *
539      * @hide
540      */
541     public static final String NAMESPACE_TARE = "tare";
542 
543     /**
544      * Telephony related properties.
545      *
546      * @hide
547      */
548     @SystemApi
549     public static final String NAMESPACE_TELEPHONY = "telephony";
550 
551     /**
552      * Namespace for TextClassifier related features.
553      *
554      * @hide
555      * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
556      */
557     @SystemApi
558     public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
559 
560     /**
561      * Namespace for contacts provider related features.
562      *
563      * @hide
564      */
565     public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
566 
567     /**
568      * Namespace for settings ui related features
569      *
570      * @hide
571      */
572     public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
573 
574     /**
575      * Namespace for android related features, i.e. for flags that affect not just a single
576      * component, but the entire system.
577      *
578      * The keys for this namespace are defined in {@link AndroidDeviceConfig}.
579      *
580      * @hide
581      */
582     @TestApi
583     public static final String NAMESPACE_ANDROID = "android";
584 
585     /**
586      * Namespace for window manager related features.
587      *
588      * @hide
589      */
590     public static final String NAMESPACE_WINDOW_MANAGER = "window_manager";
591 
592     /**
593      * Namespace for window manager features accessible by native code and
594      * loaded once per boot.
595      *
596      * @hide
597      */
598     @SystemApi
599     public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
600 
601     /**
602      * Definitions for selection toolbar related functions.
603      *
604      * @hide
605      */
606     @TestApi
607     public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
608 
609     /**
610      * Definitions for voice interaction related functions.
611      *
612      * @hide
613      */
614     public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
615 
616     /**
617      * Namespace for DevicePolicyManager related features.
618      *
619      * @hide
620      */
621     public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
622             "device_policy_manager";
623 
624     /**
625      * List of namespaces which can be read without READ_DEVICE_CONFIG permission
626      *
627      * @hide
628      */
629     @NonNull
630     private static final List<String> PUBLIC_NAMESPACES =
631             Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
632                     NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL,
633                     NAMESPACE_DEVICE_POLICY_MANAGER, NAMESPACE_CONTENT_CAPTURE);
634     /**
635      * Privacy related properties definitions.
636      *
637      * @hide
638      */
639     @SystemApi
640     public static final String NAMESPACE_PRIVACY = "privacy";
641 
642     /**
643      * Namespace for biometrics related features
644      *
645      * @hide
646      */
647     @SystemApi
648     public static final String NAMESPACE_BIOMETRICS = "biometrics";
649 
650     /**
651      * Permission related properties definitions.
652      *
653      * @hide
654      */
655     @SystemApi
656     public static final String NAMESPACE_PERMISSIONS = "permissions";
657 
658     /**
659      * Namespace for ota related features.
660      *
661      * @hide
662      */
663     @SystemApi
664     public static final String NAMESPACE_OTA = "ota";
665 
666     /**
667      * Namespace for all widget related features.
668      *
669      * @hide
670      */
671     public static final String NAMESPACE_WIDGET = "widget";
672 
673     /**
674      * Namespace for connectivity thermal power manager features.
675      *
676      * @hide
677      */
678     public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER =
679             "connectivity_thermal_power_manager";
680 
681     /**
682      * Namespace for configuration related features.
683      *
684      * @hide
685      */
686     public static final String NAMESPACE_CONFIGURATION = "configuration";
687 
688     /**
689      * LatencyTracker properties definitions.
690      *
691      * @hide
692      */
693     public static final String NAMESPACE_LATENCY_TRACKER = "latency_tracker";
694 
695     /**
696      * InteractionJankMonitor properties definitions.
697      *
698      * @hide
699      */
700     public static final String NAMESPACE_INTERACTION_JANK_MONITOR = "interaction_jank_monitor";
701 
702     /**
703      * Namespace for game overlay related features.
704      *
705      * @hide
706      */
707     public static final String NAMESPACE_GAME_OVERLAY = "game_overlay";
708 
709     /**
710      * Namespace for Android Virtualization Framework related features accessible by native code.
711      *
712      * @hide
713      */
714     public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE =
715             "virtualization_framework_native";
716 
717     /**
718      * Namespace for Constrain Display APIs related features.
719      *
720      * @hide
721      */
722     @TestApi
723     public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
724 
725     /**
726      * Namespace for App Compat Overrides related features.
727      *
728      * @hide
729      */
730     @TestApi
731     public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides";
732 
733     /**
734      * Namespace for all ultra wideband (uwb) related features.
735      *
736      * @hide
737      */
738     @SystemApi
739     public static final String NAMESPACE_UWB = "uwb";
740 
741     /**
742      * Namespace for AmbientContextEventManagerService related features.
743      *
744      * @hide
745      */
746     @SystemApi
747     public static final String NAMESPACE_AMBIENT_CONTEXT_MANAGER_SERVICE =
748             "ambient_context_manager_service";
749 
750     /**
751      * Namespace for Vendor System Native related features.
752      *
753      * @hide
754      */
755     public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
756 
757     /**
758      * Namespace for Vendor System Native Boot related features.
759      *
760      * @hide
761      */
762     public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE_BOOT = "vendor_system_native_boot";
763 
764     private static final Object sLock = new Object();
765     @GuardedBy("sLock")
766     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
767             new ArrayMap<>();
768     @GuardedBy("sLock")
769     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
770     private static final String TAG = "DeviceConfig";
771 
772     // Should never be invoked
DeviceConfig()773     private DeviceConfig() {
774     }
775 
776     /**
777      * Look up the value of a property for a particular namespace.
778      *
779      * @param namespace The namespace containing the property to look up.
780      * @param name      The name of the property to look up.
781      * @return the corresponding value, or null if not present.
782      * @hide
783      */
784     @SystemApi
785     @RequiresPermission(READ_DEVICE_CONFIG)
getProperty(@onNull String namespace, @NonNull String name)786     public static String getProperty(@NonNull String namespace, @NonNull String name) {
787         // Fetch all properties for the namespace at once and cache them in the local process, so we
788         // incur the cost of the IPC less often. Lookups happen much more frequently than updates,
789         // and we want to optimize the former.
790         return getProperties(namespace, name).getString(name, null);
791     }
792 
793     /**
794      * Look up the values of multiple properties for a particular namespace. The lookup is atomic,
795      * such that the values of these properties cannot change between the time when the first is
796      * fetched and the time when the last is fetched.
797      * <p>
798      * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none
799      * or all of the change is picked up here, but never only part of it.
800      *
801      * @param namespace The namespace containing the properties to look up.
802      * @param names     The names of properties to look up, or empty to fetch all properties for the
803      *                  given namespace.
804      * @return {@link Properties} object containing the requested properties. This reflects the
805      *     state of these properties at the time of the lookup, and is not updated to reflect any
806      *     future changes. The keyset of this Properties object will contain only the intersection
807      *     of properties already set and properties requested via the names parameter. Properties
808      *     that are already set but were not requested will not be contained here. Properties that
809      *     are not set, but were requested will not be contained here either.
810      * @hide
811      */
812     @SystemApi
813     @NonNull
814     @RequiresPermission(READ_DEVICE_CONFIG)
getProperties(@onNull String namespace, @NonNull String ... names)815     public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
816         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
817         return new Properties(namespace,
818                 Settings.Config.getStrings(contentResolver, namespace, Arrays.asList(names)));
819     }
820 
821     /**
822      * Look up the String value of a property for a particular namespace.
823      *
824      * @param namespace    The namespace containing the property to look up.
825      * @param name         The name of the property to look up.
826      * @param defaultValue The value to return if the property does not exist or has no non-null
827      *                     value.
828      * @return the corresponding value, or defaultValue if none exists.
829      * @hide
830      */
831     @SystemApi
832     @RequiresPermission(READ_DEVICE_CONFIG)
getString(@onNull String namespace, @NonNull String name, @Nullable String defaultValue)833     public static String getString(@NonNull String namespace, @NonNull String name,
834             @Nullable String defaultValue) {
835         String value = getProperty(namespace, name);
836         return value != null ? value : defaultValue;
837     }
838 
839     /**
840      * Look up the boolean value of a property for a particular namespace.
841      *
842      * @param namespace The namespace containing the property to look up.
843      * @param name      The name of the property to look up.
844      * @param defaultValue The value to return if the property does not exist or has no non-null
845      *                     value.
846      * @return the corresponding value, or defaultValue if none exists.
847      * @hide
848      */
849     @SystemApi
850     @RequiresPermission(READ_DEVICE_CONFIG)
getBoolean(@onNull String namespace, @NonNull String name, boolean defaultValue)851     public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
852             boolean defaultValue) {
853         String value = getProperty(namespace, name);
854         return value != null ? Boolean.parseBoolean(value) : defaultValue;
855     }
856 
857     /**
858      * Look up the int value of a property for a particular namespace.
859      *
860      * @param namespace The namespace containing the property to look up.
861      * @param name      The name of the property to look up.
862      * @param defaultValue The value to return if the property does not exist, has no non-null
863      *                     value, or fails to parse into an int.
864      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
865      * @hide
866      */
867     @SystemApi
868     @RequiresPermission(READ_DEVICE_CONFIG)
getInt(@onNull String namespace, @NonNull String name, int defaultValue)869     public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
870         String value = getProperty(namespace, name);
871         if (value == null) {
872             return defaultValue;
873         }
874         try {
875             return Integer.parseInt(value);
876         } catch (NumberFormatException e) {
877             Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
878             return defaultValue;
879         }
880     }
881 
882     /**
883      * Look up the long value of a property for a particular namespace.
884      *
885      * @param namespace The namespace containing the property to look up.
886      * @param name      The name of the property to look up.
887      * @param defaultValue The value to return if the property does not exist, has no non-null
888      *                     value, or fails to parse into a long.
889      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
890      * @hide
891      */
892     @SystemApi
893     @RequiresPermission(READ_DEVICE_CONFIG)
getLong(@onNull String namespace, @NonNull String name, long defaultValue)894     public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
895         String value = getProperty(namespace, name);
896         if (value == null) {
897             return defaultValue;
898         }
899         try {
900             return Long.parseLong(value);
901         } catch (NumberFormatException e) {
902             Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
903             return defaultValue;
904         }
905     }
906 
907     /**
908      * Look up the float value of a property for a particular namespace.
909      *
910      * @param namespace The namespace containing the property to look up.
911      * @param name      The name of the property to look up.
912      * @param defaultValue The value to return if the property does not exist, has no non-null
913      *                     value, or fails to parse into a float.
914      * @return the corresponding value, or defaultValue if either none exists or it does not parse.
915      * @hide
916      */
917     @SystemApi
918     @RequiresPermission(READ_DEVICE_CONFIG)
getFloat(@onNull String namespace, @NonNull String name, float defaultValue)919     public static float getFloat(@NonNull String namespace, @NonNull String name,
920             float defaultValue) {
921         String value = getProperty(namespace, name);
922         if (value == null) {
923             return defaultValue;
924         }
925         try {
926             return Float.parseFloat(value);
927         } catch (NumberFormatException e) {
928             Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
929             return defaultValue;
930         }
931     }
932 
933     /**
934      * Create a new property with the provided name and value in the provided namespace, or
935      * update the value of such a property if it already exists. The same name can exist in multiple
936      * namespaces and might have different values in any or all namespaces.
937      * <p>
938      * The method takes an argument indicating whether to make the value the default for this
939      * property.
940      * <p>
941      * All properties stored for a particular scope can be reverted to their default values
942      * by passing the namespace to {@link #resetToDefaults(int, String)}.
943      *
944      * @param namespace   The namespace containing the property to create or update.
945      * @param name        The name of the property to create or update.
946      * @param value       The value to store for the property.
947      * @param makeDefault Whether to make the new value the default one.
948      * @return {@code true} if the value was set, {@code false} if the storage implementation throws
949      * errors.
950      * @hide
951      * @see #resetToDefaults(int, String).
952      */
953     @SystemApi
954     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperty(@onNull String namespace, @NonNull String name, @Nullable String value, boolean makeDefault)955     public static boolean setProperty(@NonNull String namespace, @NonNull String name,
956             @Nullable String value, boolean makeDefault) {
957         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
958         return Settings.Config.putString(contentResolver, namespace, name, value, makeDefault);
959     }
960 
961     /**
962      * Set all of the properties for a specific namespace. Pre-existing properties will be updated
963      * and new properties will be added if necessary. Any pre-existing properties for the specific
964      * namespace which are not part of the provided {@link Properties} object will be deleted from
965      * the namespace. These changes are all applied atomically, such that no calls to read or reset
966      * these properties can happen in the middle of this update.
967      * <p>
968      * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either
969      * none or all of this update is picked up, but never only part of it.
970      *
971      * @param properties the complete set of properties to set for a specific namespace.
972      * @throws BadConfigException if the provided properties are banned by RescueParty.
973      * @return {@code true} if the values were set, {@code false} otherwise.
974      * @hide
975      */
976     @SystemApi
977     @RequiresPermission(WRITE_DEVICE_CONFIG)
setProperties(@onNull Properties properties)978     public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
979         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
980         return Settings.Config.setStrings(contentResolver, properties.getNamespace(),
981                 properties.mMap);
982     }
983 
984     /**
985      * Delete a property with the provided name and value in the provided namespace
986      *
987      * @param namespace   The namespace containing the property to delete.
988      * @param name        The name of the property to delete.
989      * @return {@code true} if the property was deleted or it did not exist in the first place.
990      * Return {@code false} if the storage implementation throws errors.
991      * @hide
992      */
993     @SystemApi
994     @RequiresPermission(WRITE_DEVICE_CONFIG)
deleteProperty(@onNull String namespace, @NonNull String name)995     public static boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
996         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
997         return Settings.Config.deleteString(contentResolver, namespace, name);
998     }
999 
1000     /**
1001      * Reset properties to their default values by removing the underlying values.
1002      * <p>
1003      * The method accepts an optional namespace parameter. If provided, only properties set within
1004      * that namespace will be reset. Otherwise, all properties will be reset.
1005      * <p>
1006      * Note: This method should only be used by {@link com.android.server.RescueParty}. It was
1007      * designed to be used in the event of boot or crash loops caused by flag changes. It does not
1008      * revert flag values to defaults - instead it removes the property entirely which causes the
1009      * consumer of the flag to use hardcoded defaults upon retrieval.
1010      * <p>
1011      * To clear values for a namespace without removing the underlying properties, construct a
1012      * {@link Properties} object with the caller's namespace and either an empty flag map, or some
1013      * snapshot of flag values. Then use {@link #setProperties(Properties)} to remove all flags
1014      * under the namespace, or set them to the values in the snapshot.
1015      * <p>
1016      * To revert values for testing, one should mock DeviceConfig using
1017      * {@link com.android.server.testables.TestableDeviceConfig} where possible. Otherwise, fallback
1018      * to using {@link #setProperties(Properties)} as outlined above.
1019      *
1020      * @param resetMode The reset mode to use.
1021      * @param namespace Optionally, the specific namespace which resets will be limited to.
1022      * @hide
1023      * @see #setProperty(String, String, String, boolean)
1024      */
1025     @SystemApi
1026     @RequiresPermission(WRITE_DEVICE_CONFIG)
resetToDefaults(@esetMode int resetMode, @Nullable String namespace)1027     public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
1028         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
1029         Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
1030     }
1031 
1032     /**
1033      * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device
1034      * config values. This is intended for use during tests to prevent a sync operation clearing
1035      * config values which could influence the outcome of the tests, i.e. by changing behavior.
1036      *
1037      * @param syncDisabledMode the mode to use, see {@link Settings.Config#SYNC_DISABLED_MODE_NONE},
1038      *     {@link Settings.Config#SYNC_DISABLED_MODE_PERSISTENT} and {@link
1039      *     Settings.Config#SYNC_DISABLED_MODE_UNTIL_REBOOT}
1040      *
1041      * @see #getSyncDisabledMode()
1042      * @hide
1043      */
1044     @RequiresPermission(WRITE_DEVICE_CONFIG)
setSyncDisabledMode(@yncDisabledMode int syncDisabledMode)1045     public static void setSyncDisabledMode(@SyncDisabledMode int syncDisabledMode) {
1046         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
1047         Settings.Config.setSyncDisabledMode(contentResolver, syncDisabledMode);
1048     }
1049 
1050     /**
1051      * Returns the current mode of sync disabling.
1052      *
1053      * @see #setSyncDisabledMode(int)
1054      * @hide
1055      */
1056     @RequiresPermission(WRITE_DEVICE_CONFIG)
getSyncDisabledMode()1057     public static @SyncDisabledMode int getSyncDisabledMode() {
1058         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
1059         return Settings.Config.getSyncDisabledMode(contentResolver);
1060     }
1061 
1062     /**
1063      * Add a listener for property changes.
1064      * <p>
1065      * This listener will be called whenever properties in the specified namespace change. Callbacks
1066      * will be made on the specified executor. Future calls to this method with the same listener
1067      * will replace the old namespace and executor. Remove the listener entirely by calling
1068      * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
1069      *
1070      * @param namespace                   The namespace containing properties to monitor.
1071      * @param executor                    The executor which will be used to run callbacks.
1072      * @param onPropertiesChangedListener The listener to add.
1073      * @hide
1074      * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
1075      */
1076     @SystemApi
1077     @RequiresPermission(READ_DEVICE_CONFIG)
addOnPropertiesChangedListener( @onNull String namespace, @NonNull @CallbackExecutor Executor executor, @NonNull OnPropertiesChangedListener onPropertiesChangedListener)1078     public static void addOnPropertiesChangedListener(
1079             @NonNull String namespace,
1080             @NonNull @CallbackExecutor Executor executor,
1081             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
1082         enforceReadPermission(ActivityThread.currentApplication().getApplicationContext(),
1083                 namespace);
1084         synchronized (sLock) {
1085             Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
1086             if (oldNamespace == null) {
1087                 // Brand new listener, add it to the list.
1088                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1089                 incrementNamespace(namespace);
1090             } else if (namespace.equals(oldNamespace.first)) {
1091                 // Listener is already registered for this namespace, update executor just in case.
1092                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1093             } else {
1094                 // Update this listener from an old namespace to the new one.
1095                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
1096                 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
1097                 incrementNamespace(namespace);
1098             }
1099         }
1100     }
1101 
1102     /**
1103      * Remove a listener for property changes. The listener will receive no further notification of
1104      * property changes.
1105      *
1106      * @param onPropertiesChangedListener The listener to remove.
1107      * @hide
1108      * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
1109      */
1110     @SystemApi
removeOnPropertiesChangedListener( @onNull OnPropertiesChangedListener onPropertiesChangedListener)1111     public static void removeOnPropertiesChangedListener(
1112             @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
1113         Preconditions.checkNotNull(onPropertiesChangedListener);
1114         synchronized (sLock) {
1115             if (sListeners.containsKey(onPropertiesChangedListener)) {
1116                 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
1117                 sListeners.remove(onPropertiesChangedListener);
1118             }
1119         }
1120     }
1121 
createNamespaceUri(@onNull String namespace)1122     private static Uri createNamespaceUri(@NonNull String namespace) {
1123         Preconditions.checkNotNull(namespace);
1124         return CONTENT_URI.buildUpon().appendPath(namespace).build();
1125     }
1126 
1127     /**
1128      * Increment the count used to represent the number of listeners subscribed to the given
1129      * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a
1130      * ContentObserver is registered.
1131      *
1132      * @param namespace The namespace to increment the count for.
1133      */
1134     @GuardedBy("sLock")
incrementNamespace(@onNull String namespace)1135     private static void incrementNamespace(@NonNull String namespace) {
1136         Preconditions.checkNotNull(namespace);
1137         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
1138         if (namespaceCount != null) {
1139             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
1140         } else {
1141             // This is a new namespace, register a ContentObserver for it.
1142             ContentObserver contentObserver = new ContentObserver(null) {
1143                 @Override
1144                 public void onChange(boolean selfChange, Uri uri) {
1145                     if (uri != null) {
1146                         handleChange(uri);
1147                     }
1148                 }
1149             };
1150             ActivityThread.currentApplication().getContentResolver()
1151                     .registerContentObserver(createNamespaceUri(namespace), true, contentObserver);
1152             sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
1153         }
1154     }
1155 
1156     /**
1157      * Decrement the count used to represent the number of listeners subscribed to the given
1158      * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given
1159      * namespace, the ContentObserver that had been tracking it will be removed.
1160      *
1161      * @param namespace The namespace to decrement the count for.
1162      */
1163     @GuardedBy("sLock")
decrementNamespace(@onNull String namespace)1164     private static void decrementNamespace(@NonNull String namespace) {
1165         Preconditions.checkNotNull(namespace);
1166         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
1167         if (namespaceCount == null) {
1168             // This namespace is not registered and does not need to be decremented
1169             return;
1170         } else if (namespaceCount.second > 1) {
1171             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
1172         } else {
1173             // Decrementing a namespace to zero means we no longer need its ContentObserver.
1174             ActivityThread.currentApplication().getContentResolver()
1175                     .unregisterContentObserver(namespaceCount.first);
1176             sNamespaces.remove(namespace);
1177         }
1178     }
1179 
handleChange(@onNull Uri uri)1180     private static void handleChange(@NonNull Uri uri) {
1181         Preconditions.checkNotNull(uri);
1182         List<String> pathSegments = uri.getPathSegments();
1183         // pathSegments(0) is "config"
1184         final String namespace = pathSegments.get(1);
1185         Properties.Builder propBuilder = new Properties.Builder(namespace);
1186         try {
1187             Properties allProperties = getProperties(namespace);
1188             for (int i = 2; i < pathSegments.size(); ++i) {
1189                 String key = pathSegments.get(i);
1190                 propBuilder.setString(key, allProperties.getString(key, null));
1191             }
1192         } catch (SecurityException e) {
1193             // Silently failing to not crash binder or listener threads.
1194             Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
1195             return;
1196         }
1197         Properties properties = propBuilder.build();
1198 
1199         synchronized (sLock) {
1200             for (int i = 0; i < sListeners.size(); i++) {
1201                 if (namespace.equals(sListeners.valueAt(i).first)) {
1202                     final OnPropertiesChangedListener listener = sListeners.keyAt(i);
1203                     sListeners.valueAt(i).second.execute(() -> {
1204                         listener.onPropertiesChanged(properties);
1205                     });
1206                 }
1207             }
1208         }
1209     }
1210 
1211     /**
1212      * Enforces READ_DEVICE_CONFIG permission if namespace is not one of public namespaces.
1213      * @hide
1214      */
enforceReadPermission(Context context, String namespace)1215     public static void enforceReadPermission(Context context, String namespace) {
1216         if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
1217                 != PackageManager.PERMISSION_GRANTED) {
1218             if (!PUBLIC_NAMESPACES.contains(namespace)) {
1219                 throw new SecurityException("Permission denial: reading from settings requires:"
1220                         + READ_DEVICE_CONFIG);
1221             }
1222         }
1223     }
1224 
1225     /**
1226      * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION;
1227      * @hide
1228      */
getPublicNamespaces()1229     public static @NonNull List<String> getPublicNamespaces() {
1230         return PUBLIC_NAMESPACES;
1231     }
1232 
1233     /**
1234      * Interface for monitoring changes to properties. Implementations will receive callbacks when
1235      * properties change, including a {@link Properties} object which contains a single namespace
1236      * and all of the properties which changed for that namespace. This includes properties which
1237      * were added, updated, or deleted. This is not necessarily a complete list of all properties
1238      * belonging to the namespace, as properties which don't change are omitted.
1239      * <p>
1240      * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
1241      *
1242      * @hide
1243      */
1244     @SystemApi
1245     public interface OnPropertiesChangedListener {
1246         /**
1247          * Called when one or more properties have changed, providing a Properties object with all
1248          * of the changed properties. This object will contain only properties which have changed,
1249          * not the complete set of all properties belonging to the namespace.
1250          *
1251          * @param properties Contains the complete collection of properties which have changed for a
1252          *                   single namespace. This includes only those which were added, updated,
1253          *                   or deleted.
1254          */
onPropertiesChanged(@onNull Properties properties)1255         void onPropertiesChanged(@NonNull Properties properties);
1256     }
1257 
1258     /**
1259      * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This
1260      * happens if RescueParty has identified a bad configuration and reset the namespace.
1261      *
1262      * @hide
1263      */
1264     @SystemApi
1265     public static class BadConfigException extends Exception {}
1266 
1267     /**
1268      * A mapping of properties to values, as well as a single namespace which they all belong to.
1269      *
1270      * @hide
1271      */
1272     @SystemApi
1273     public static class Properties {
1274         private final String mNamespace;
1275         private final HashMap<String, String> mMap;
1276         private Set<String> mKeyset;
1277 
1278         /**
1279          * Create a mapping of properties to values and the namespace they belong to.
1280          *
1281          * @param namespace The namespace these properties belong to.
1282          * @param keyValueMap A map between property names and property values.
1283          * @hide
1284          */
Properties(@onNull String namespace, @Nullable Map<String, String> keyValueMap)1285         public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
1286             Preconditions.checkNotNull(namespace);
1287             mNamespace = namespace;
1288             mMap = new HashMap();
1289             if (keyValueMap != null) {
1290                 mMap.putAll(keyValueMap);
1291             }
1292         }
1293 
1294         /**
1295          * @return the namespace all properties within this instance belong to.
1296          */
1297         @NonNull
getNamespace()1298         public String getNamespace() {
1299             return mNamespace;
1300         }
1301 
1302         /**
1303          * @return the non-null set of property names.
1304          */
1305         @NonNull
getKeyset()1306         public Set<String> getKeyset() {
1307             if (mKeyset == null) {
1308                 mKeyset = Collections.unmodifiableSet(mMap.keySet());
1309             }
1310             return mKeyset;
1311         }
1312 
1313         /**
1314          * Look up the String value of a property.
1315          *
1316          * @param name         The name of the property to look up.
1317          * @param defaultValue The value to return if the property has not been defined.
1318          * @return the corresponding value, or defaultValue if none exists.
1319          */
1320         @Nullable
getString(@onNull String name, @Nullable String defaultValue)1321         public String getString(@NonNull String name, @Nullable String defaultValue) {
1322             Preconditions.checkNotNull(name);
1323             String value = mMap.get(name);
1324             return value != null ? value : defaultValue;
1325         }
1326 
1327         /**
1328          * Look up the boolean value of a property.
1329          *
1330          * @param name         The name of the property to look up.
1331          * @param defaultValue The value to return if the property has not been defined.
1332          * @return the corresponding value, or defaultValue if none exists.
1333          */
getBoolean(@onNull String name, boolean defaultValue)1334         public boolean getBoolean(@NonNull String name, boolean defaultValue) {
1335             Preconditions.checkNotNull(name);
1336             String value = mMap.get(name);
1337             return value != null ? Boolean.parseBoolean(value) : defaultValue;
1338         }
1339 
1340         /**
1341          * Look up the int value of a property.
1342          *
1343          * @param name         The name of the property to look up.
1344          * @param defaultValue The value to return if the property has not been defined or fails to
1345          *                     parse into an int.
1346          * @return the corresponding value, or defaultValue if no valid int is available.
1347          */
getInt(@onNull String name, int defaultValue)1348         public int getInt(@NonNull String name, int defaultValue) {
1349             Preconditions.checkNotNull(name);
1350             String value = mMap.get(name);
1351             if (value == null) {
1352                 return defaultValue;
1353             }
1354             try {
1355                 return Integer.parseInt(value);
1356             } catch (NumberFormatException e) {
1357                 Log.e(TAG, "Parsing int failed for " + name);
1358                 return defaultValue;
1359             }
1360         }
1361 
1362         /**
1363          * Look up the long value of a property.
1364          *
1365          * @param name         The name of the property to look up.
1366          * @param defaultValue The value to return if the property has not been defined. or fails to
1367          *                     parse into a long.
1368          * @return the corresponding value, or defaultValue if no valid long is available.
1369          */
getLong(@onNull String name, long defaultValue)1370         public long getLong(@NonNull String name, long defaultValue) {
1371             Preconditions.checkNotNull(name);
1372             String value = mMap.get(name);
1373             if (value == null) {
1374                 return defaultValue;
1375             }
1376             try {
1377                 return Long.parseLong(value);
1378             } catch (NumberFormatException e) {
1379                 Log.e(TAG, "Parsing long failed for " + name);
1380                 return defaultValue;
1381             }
1382         }
1383 
1384         /**
1385          * Look up the int value of a property.
1386          *
1387          * @param name         The name of the property to look up.
1388          * @param defaultValue The value to return if the property has not been defined. or fails to
1389          *                     parse into a float.
1390          * @return the corresponding value, or defaultValue if no valid float is available.
1391          */
getFloat(@onNull String name, float defaultValue)1392         public float getFloat(@NonNull String name, float defaultValue) {
1393             Preconditions.checkNotNull(name);
1394             String value = mMap.get(name);
1395             if (value == null) {
1396                 return defaultValue;
1397             }
1398             try {
1399                 return Float.parseFloat(value);
1400             } catch (NumberFormatException e) {
1401                 Log.e(TAG, "Parsing float failed for " + name);
1402                 return defaultValue;
1403             }
1404         }
1405 
1406         /**
1407          * Builder class for the construction of {@link Properties} objects.
1408          */
1409         public static final class Builder {
1410             @NonNull
1411             private final String mNamespace;
1412             @NonNull
1413             private final Map<String, String> mKeyValues = new HashMap<>();
1414 
1415             /**
1416              * Create a new Builders for the specified namespace.
1417              * @param namespace non null namespace.
1418              */
Builder(@onNull String namespace)1419             public Builder(@NonNull String namespace) {
1420                 mNamespace = namespace;
1421             }
1422 
1423             /**
1424              * Add a new property with the specified key and value.
1425              * @param name non null name of the property.
1426              * @param value nullable string value of the property.
1427              * @return this Builder object
1428              */
1429             @NonNull
setString(@onNull String name, @Nullable String value)1430             public Builder setString(@NonNull String name, @Nullable String value) {
1431                 mKeyValues.put(name, value);
1432                 return this;
1433             }
1434 
1435             /**
1436              * Add a new property with the specified key and value.
1437              * @param name non null name of the property.
1438              * @param value nullable string value of the property.
1439              * @return this Builder object
1440              */
1441             @NonNull
setBoolean(@onNull String name, boolean value)1442             public Builder setBoolean(@NonNull String name, boolean value) {
1443                 mKeyValues.put(name, Boolean.toString(value));
1444                 return this;
1445             }
1446 
1447             /**
1448              * Add a new property with the specified key and value.
1449              * @param name non null name of the property.
1450              * @param value int value of the property.
1451              * @return this Builder object
1452              */
1453             @NonNull
setInt(@onNull String name, int value)1454             public Builder setInt(@NonNull String name, int value) {
1455                 mKeyValues.put(name, Integer.toString(value));
1456                 return this;
1457             }
1458 
1459             /**
1460              * Add a new property with the specified key and value.
1461              * @param name non null name of the property.
1462              * @param value long value of the property.
1463              * @return this Builder object
1464              */
1465             @NonNull
setLong(@onNull String name, long value)1466             public Builder setLong(@NonNull String name, long value) {
1467                 mKeyValues.put(name, Long.toString(value));
1468                 return this;
1469             }
1470 
1471             /**
1472              * Add a new property with the specified key and value.
1473              * @param name non null name of the property.
1474              * @param value float value of the property.
1475              * @return this Builder object
1476              */
1477             @NonNull
setFloat(@onNull String name, float value)1478             public Builder setFloat(@NonNull String name, float value) {
1479                 mKeyValues.put(name, Float.toString(value));
1480                 return this;
1481             }
1482 
1483             /**
1484              * Create a new {@link Properties} object.
1485              * @return non null Properties.
1486              */
1487             @NonNull
build()1488             public Properties build() {
1489                 return new Properties(mNamespace, mKeyValues);
1490             }
1491         }
1492     }
1493 
1494 }
1495