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