2 * Copyright (C) 2018 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.provider;
19 import static android.Manifest.permission.READ_DEVICE_CONFIG;
20 import static android.Manifest.permission.WRITE_DEVICE_CONFIG;
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.ResetMode;
35 import android.util.ArrayMap;
36 import android.util.Log;
37 import android.util.Pair;
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.util.Preconditions;
42 import java.util.Arrays;
43 import java.util.HashMap;
44 import java.util.List;
47 import java.util.concurrent.Executor;
50 * Device level configuration parameters which can be tuned by a separate configuration service.
51 * Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used
52 * by native code and should be pushed to system properties to make them accessible.
58 public final class DeviceConfig {
60 * The content:// style URL for the config table.
64 public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
67 * Namespace for activity manager related features. These features will be applied
68 * immediately upon change.
73 public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
76 * Namespace for all activity manager related features that are used at the native level.
77 * These features are applied at reboot.
82 public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT =
83 "activity_manager_native_boot";
86 * Namespace for all app compat related features. These features will be applied
87 * immediately upon change.
92 public static final String NAMESPACE_APP_COMPAT = "app_compat";
95 * Namespace for AttentionManagerService related features.
100 public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
103 * Namespace for autofill feature that provides suggestions across all apps when
104 * the user interacts with input fields.
110 public static final String NAMESPACE_AUTOFILL = "autofill";
113 * Namespace for all networking connectivity related features.
118 public static final String NAMESPACE_CONNECTIVITY = "connectivity";
121 * Namespace for content capture feature used by on-device machine intelligence
122 * to provide suggestions in a privacy-safe manner.
128 public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
131 * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
136 public static final String NAMESPACE_DEX_BOOT = "dex_boot";
139 * Namespace for display manager related features. The names to access the properties in this
140 * namespace should be defined in {@link android.hardware.display.DisplayManager}.
144 public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
147 * Namespace for all Game Driver features.
152 public static final String NAMESPACE_GAME_DRIVER = "game_driver";
155 * Namespace for all input-related features that are used at the native level.
156 * These features are applied at reboot.
161 public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
164 * Namespace for attention-based features provided by on-device machine intelligence.
169 public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
172 * Definitions for properties related to Content Suggestions.
176 public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS =
177 "intelligence_content_suggestions";
180 * Namespace for all media native related features.
185 public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
188 * Namespace for all netd related features.
193 public static final String NAMESPACE_NETD_NATIVE = "netd_native";
196 * Namespace for Rollback flags that are applied immediately.
201 public static final String NAMESPACE_ROLLBACK = "rollback";
204 * Namespace for Rollback flags that are applied after a reboot.
209 public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
212 * Namespace for all runtime related features that don't require a reboot to become active.
213 * There are no feature flags using NAMESPACE_RUNTIME.
218 public static final String NAMESPACE_RUNTIME = "runtime";
221 * Namespace for all runtime related features that require system properties for accessing
222 * the feature flags from C++ or Java language code. One example is the app image startup
223 * cache feature use_app_image_startup_cache.
228 public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
231 * Namespace for all runtime native boot related features. Boot in this case refers to the
232 * fact that the properties only take affect after rebooting the device.
237 public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
240 * Namespace for system scheduler related features. These features will be applied
241 * immediately upon change.
246 public static final String NAMESPACE_SCHEDULER = "scheduler";
249 * Namespace for storage-related features.
254 public static final String NAMESPACE_STORAGE = "storage";
257 * Namespace for System UI related features.
262 public static final String NAMESPACE_SYSTEMUI = "systemui";
265 * Telephony related properties.
270 public static final String NAMESPACE_TELEPHONY = "telephony";
273 * Namespace for TextClassifier related features.
276 * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
279 public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
282 * Namespace for contacts provider related features.
286 public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
289 * Namespace for settings ui related features
293 public static final String NAMESPACE_SETTINGS_UI = "settings_ui";
296 * Namespace for window manager related features. The names to access the properties in this
297 * namespace should be defined in {@link WindowManager}.
302 public static final String NAMESPACE_WINDOW_MANAGER = "android:window_manager";
305 * List of namespaces which can be read without READ_DEVICE_CONFIG permission
310 private static final List<String> PUBLIC_NAMESPACES =
311 Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME);
313 * Privacy related properties definitions.
319 public static final String NAMESPACE_PRIVACY = "privacy";
322 * Interface for accessing keys belonging to {@link #NAMESPACE_WINDOW_MANAGER}.
326 public interface WindowManager {
329 * Key for accessing the system gesture exclusion limit (an integer in dp).
331 * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
335 String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
338 * Key for controlling whether system gestures are implicitly excluded by windows requesting
339 * sticky immersive mode from apps that are targeting an SDK prior to Q.
341 * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
345 String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE =
346 "system_gestures_excluded_by_pre_q_sticky_immersive";
349 * The minimum duration between gesture exclusion logging for a given window in
352 * Events that happen in-between will be silently dropped.
354 * A non-positive value disables logging.
356 * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
359 String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS =
360 "system_gesture_exclusion_log_debounce_millis";
363 private static final Object sLock = new Object();
365 private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
368 private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
371 private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
372 private static final String TAG = "DeviceConfig";
374 // Should never be invoked
375 private DeviceConfig() {
379 * Look up the value of a property for a particular namespace.
381 * @param namespace The namespace containing the property to look up.
382 * @param name The name of the property to look up.
383 * @return the corresponding value, or null if not present.
388 @RequiresPermission(READ_DEVICE_CONFIG)
389 public static String getProperty(@NonNull String namespace, @NonNull String name) {
390 ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
391 String compositeName = createCompositeName(namespace, name);
392 return Settings.Config.getString(contentResolver, compositeName);
396 * Look up the String value of a property for a particular namespace.
398 * @param namespace The namespace containing the property to look up.
399 * @param name The name of the property to look up.
400 * @param defaultValue The value to return if the property does not exist or has no non-null
402 * @return the corresponding value, or defaultValue if none exists.
407 @RequiresPermission(READ_DEVICE_CONFIG)
408 public static String getString(@NonNull String namespace, @NonNull String name,
409 @Nullable String defaultValue) {
410 String value = getProperty(namespace, name);
411 return value != null ? value : defaultValue;
415 * Look up the boolean value of a property for a particular namespace.
417 * @param namespace The namespace containing the property to look up.
418 * @param name The name of the property to look up.
419 * @param defaultValue The value to return if the property does not exist or has no non-null
421 * @return the corresponding value, or defaultValue if none exists.
426 @RequiresPermission(READ_DEVICE_CONFIG)
427 public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
428 boolean defaultValue) {
429 String value = getProperty(namespace, name);
430 return value != null ? Boolean.parseBoolean(value) : defaultValue;
434 * Look up the int value of a property for a particular namespace.
436 * @param namespace The namespace containing the property to look up.
437 * @param name The name of the property to look up.
438 * @param defaultValue The value to return if the property does not exist, has no non-null
439 * value, or fails to parse into an int.
440 * @return the corresponding value, or defaultValue if either none exists or it does not parse.
445 @RequiresPermission(READ_DEVICE_CONFIG)
446 public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
447 String value = getProperty(namespace, name);
452 return Integer.parseInt(value);
453 } catch (NumberFormatException e) {
454 Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
460 * Look up the long value of a property for a particular namespace.
462 * @param namespace The namespace containing the property to look up.
463 * @param name The name of the property to look up.
464 * @param defaultValue The value to return if the property does not exist, has no non-null
465 * value, or fails to parse into a long.
466 * @return the corresponding value, or defaultValue if either none exists or it does not parse.
471 @RequiresPermission(READ_DEVICE_CONFIG)
472 public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
473 String value = getProperty(namespace, name);
478 return Long.parseLong(value);
479 } catch (NumberFormatException e) {
480 Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
486 * Look up the float value of a property for a particular namespace.
488 * @param namespace The namespace containing the property to look up.
489 * @param name The name of the property to look up.
490 * @param defaultValue The value to return if the property does not exist, has no non-null
491 * value, or fails to parse into a float.
492 * @return the corresponding value, or defaultValue if either none exists or it does not parse.
497 @RequiresPermission(READ_DEVICE_CONFIG)
498 public static float getFloat(@NonNull String namespace, @NonNull String name,
499 float defaultValue) {
500 String value = getProperty(namespace, name);
505 return Float.parseFloat(value);
506 } catch (NumberFormatException e) {
507 Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
513 * Create a new property with the the provided name and value in the provided namespace, or
514 * update the value of such a property if it already exists. The same name can exist in multiple
515 * namespaces and might have different values in any or all namespaces.
517 * The method takes an argument indicating whether to make the value the default for this
520 * All properties stored for a particular scope can be reverted to their default values
521 * by passing the namespace to {@link #resetToDefaults(int, String)}.
523 * @param namespace The namespace containing the property to create or update.
524 * @param name The name of the property to create or update.
525 * @param value The value to store for the property.
526 * @param makeDefault Whether to make the new value the default one.
527 * @return True if the value was set, false if the storage implementation throws errors.
529 * @see #resetToDefaults(int, String).
533 @RequiresPermission(WRITE_DEVICE_CONFIG)
534 public static boolean setProperty(@NonNull String namespace, @NonNull String name,
535 @Nullable String value, boolean makeDefault) {
536 String compositeName = createCompositeName(namespace, name);
537 ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
538 return Settings.Config.putString(contentResolver, compositeName, value, makeDefault);
542 * Reset properties to their default values.
544 * The method accepts an optional namespace parameter. If provided, only properties set within
545 * that namespace will be reset. Otherwise, all properties will be reset.
547 * @param resetMode The reset mode to use.
548 * @param namespace Optionally, the specific namespace which resets will be limited to.
550 * @see #setProperty(String, String, String, boolean)
554 @RequiresPermission(WRITE_DEVICE_CONFIG)
555 public static void resetToDefaults(@ResetMode int resetMode, @Nullable String namespace) {
556 ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
557 Settings.Config.resetToDefaults(contentResolver, resetMode, namespace);
561 * Add a listener for property changes.
563 * This listener will be called whenever properties in the specified namespace change. Callbacks
564 * will be made on the specified executor. Future calls to this method with the same listener
565 * will replace the old namespace and executor. Remove the listener entirely by calling
566 * {@link #removeOnPropertyChangedListener(OnPropertyChangedListener)}.
568 * @param namespace The namespace containing properties to monitor.
569 * @param executor The executor which will be used to run callbacks.
570 * @param onPropertyChangedListener The listener to add.
572 * @see #removeOnPropertyChangedListener(OnPropertyChangedListener)
577 @RequiresPermission(READ_DEVICE_CONFIG)
578 public static void addOnPropertyChangedListener(
579 @NonNull String namespace,
580 @NonNull @CallbackExecutor Executor executor,
581 @NonNull OnPropertyChangedListener onPropertyChangedListener) {
582 enforceReadPermission(ActivityThread.currentApplication().getApplicationContext(),
584 synchronized (sLock) {
585 Pair<String, Executor> oldNamespace = sSingleListeners.get(onPropertyChangedListener);
586 if (oldNamespace == null) {
587 // Brand new listener, add it to the list.
588 sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
589 incrementNamespace(namespace);
590 } else if (namespace.equals(oldNamespace.first)) {
591 // Listener is already registered for this namespace, update executor just in case.
592 sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
594 // Update this listener from an old namespace to the new one.
595 decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
596 sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
597 incrementNamespace(namespace);
603 * Add a listener for property changes.
605 * This listener will be called whenever properties in the specified namespace change. Callbacks
606 * will be made on the specified executor. Future calls to this method with the same listener
607 * will replace the old namespace and executor. Remove the listener entirely by calling
608 * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
610 * @param namespace The namespace containing properties to monitor.
611 * @param executor The executor which will be used to run callbacks.
612 * @param onPropertiesChangedListener The listener to add.
614 * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
618 @RequiresPermission(READ_DEVICE_CONFIG)
619 public static void addOnPropertiesChangedListener(
620 @NonNull String namespace,
621 @NonNull @CallbackExecutor Executor executor,
622 @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
623 enforceReadPermission(ActivityThread.currentApplication().getApplicationContext(),
625 synchronized (sLock) {
626 Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
627 if (oldNamespace == null) {
628 // Brand new listener, add it to the list.
629 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
630 incrementNamespace(namespace);
631 } else if (namespace.equals(oldNamespace.first)) {
632 // Listener is already registered for this namespace, update executor just in case.
633 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
635 // Update this listener from an old namespace to the new one.
636 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
637 sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
638 incrementNamespace(namespace);
644 * Remove a listener for property changes. The listener will receive no further notification of
647 * @param onPropertyChangedListener The listener to remove.
649 * @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener)
654 public static void removeOnPropertyChangedListener(
655 @NonNull OnPropertyChangedListener onPropertyChangedListener) {
656 Preconditions.checkNotNull(onPropertyChangedListener);
657 synchronized (sLock) {
658 if (sSingleListeners.containsKey(onPropertyChangedListener)) {
659 decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
660 sSingleListeners.remove(onPropertyChangedListener);
666 * Remove a listener for property changes. The listener will receive no further notification of
669 * @param onPropertiesChangedListener The listener to remove.
671 * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
675 public static void removeOnPropertiesChangedListener(
676 @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
677 Preconditions.checkNotNull(onPropertiesChangedListener);
678 synchronized (sLock) {
679 if (sListeners.containsKey(onPropertiesChangedListener)) {
680 decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
681 sListeners.remove(onPropertiesChangedListener);
686 private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
687 Preconditions.checkNotNull(namespace);
688 Preconditions.checkNotNull(name);
689 return namespace + "/" + name;
692 private static Uri createNamespaceUri(@NonNull String namespace) {
693 Preconditions.checkNotNull(namespace);
694 return CONTENT_URI.buildUpon().appendPath(namespace).build();
698 * Increment the count used to represent the number of listeners subscribed to the given
699 * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a
700 * ContentObserver is registered.
702 * @param namespace The namespace to increment the count for.
705 private static void incrementNamespace(@NonNull String namespace) {
706 Preconditions.checkNotNull(namespace);
707 Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
708 if (namespaceCount != null) {
709 sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
711 // This is a new namespace, register a ContentObserver for it.
712 ContentObserver contentObserver = new ContentObserver(null) {
714 public void onChange(boolean selfChange, Uri uri) {
720 ActivityThread.currentApplication().getContentResolver()
721 .registerContentObserver(createNamespaceUri(namespace), true, contentObserver);
722 sNamespaces.put(namespace, new Pair<>(contentObserver, 1));
727 * Decrement the count used to represent the number of listeners subscribed to the given
728 * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given
729 * namespace, the ContentObserver that had been tracking it will be removed.
731 * @param namespace The namespace to decrement the count for.
734 private static void decrementNamespace(@NonNull String namespace) {
735 Preconditions.checkNotNull(namespace);
736 Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
737 if (namespaceCount == null) {
738 // This namespace is not registered and does not need to be decremented
740 } else if (namespaceCount.second > 1) {
741 sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1));
743 // Decrementing a namespace to zero means we no longer need its ContentObserver.
744 ActivityThread.currentApplication().getContentResolver()
745 .unregisterContentObserver(namespaceCount.first);
746 sNamespaces.remove(namespace);
750 private static void handleChange(@NonNull Uri uri) {
751 Preconditions.checkNotNull(uri);
752 List<String> pathSegments = uri.getPathSegments();
753 // pathSegments(0) is "config"
754 final String namespace = pathSegments.get(1);
755 final String name = pathSegments.get(2);
758 value = getProperty(namespace, name);
759 } catch (SecurityException e) {
760 // Silently failing to not crash binder or listener threads.
761 Log.e(TAG, "OnPropertyChangedListener update failed: permission violation.");
764 synchronized (sLock) {
765 // OnPropertiesChangedListeners
766 for (int i = 0; i < sListeners.size(); i++) {
767 if (namespace.equals(sListeners.valueAt(i).first)) {
769 sListeners.valueAt(i).second.execute(new Runnable() {
772 Map<String, String> propertyMap = new HashMap(1);
773 propertyMap.put(name, value);
775 .onPropertiesChanged(new Properties(namespace, propertyMap));
781 // OnPropertyChangedListeners
782 for (int i = 0; i < sSingleListeners.size(); i++) {
783 if (namespace.equals(sSingleListeners.valueAt(i).first)) {
785 sSingleListeners.valueAt(i).second.execute(new Runnable() {
788 sSingleListeners.keyAt(j).onPropertyChanged(namespace, name, value);
799 * Enforces READ_DEVICE_CONFIG permission if namespace is not one of public namespaces.
802 public static void enforceReadPermission(Context context, String namespace) {
803 if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
804 != PackageManager.PERMISSION_GRANTED) {
805 if (!PUBLIC_NAMESPACES.contains(namespace)) {
806 throw new SecurityException("Permission denial: reading from settings requires:"
807 + READ_DEVICE_CONFIG);
814 * Interface for monitoring single property changes.
816 * Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes.
823 public interface OnPropertyChangedListener {
825 * Called when a property has changed.
827 * @param namespace The namespace containing the property which has changed.
828 * @param name The name of the property which has changed.
829 * @param value The new value of the property which has changed.
831 void onPropertyChanged(@NonNull String namespace, @NonNull String name,
832 @Nullable String value);
836 * Interface for monitoring changes to properties.
838 * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
844 public interface OnPropertiesChangedListener {
846 * Called when one or more properties have changed.
848 * @param properties Contains the complete collection of properties which have changed for a
851 void onPropertiesChanged(@NonNull Properties properties);
855 * A mapping of properties to values, as well as a single namespace which they all belong to.
861 public static class Properties {
862 private final String mNamespace;
863 private final HashMap<String, String> mMap;
866 * Create a mapping of properties to values and the namespace they belong to.
868 * @param namespace The namespace these properties belong to.
869 * @param keyValueMap A map between property names and property values.
871 Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) {
872 Preconditions.checkNotNull(namespace);
873 mNamespace = namespace;
874 mMap = new HashMap();
875 if (keyValueMap != null) {
876 mMap.putAll(keyValueMap);
881 * @return the namespace all properties within this instance belong to.
884 public String getNamespace() {
889 * @return the non-null set of property names.
892 public Set<String> getKeyset() {
893 return mMap.keySet();
897 * Look up the String value of a property.
899 * @param name The name of the property to look up.
900 * @param defaultValue The value to return if the property has not been defined.
901 * @return the corresponding value, or defaultValue if none exists.
904 public String getString(@NonNull String name, @Nullable String defaultValue) {
905 Preconditions.checkNotNull(name);
906 String value = mMap.get(name);
907 return value != null ? value : defaultValue;
911 * Look up the boolean value of a property.
913 * @param name The name of the property to look up.
914 * @param defaultValue The value to return if the property has not been defined.
915 * @return the corresponding value, or defaultValue if none exists.
917 public boolean getBoolean(@NonNull String name, boolean defaultValue) {
918 Preconditions.checkNotNull(name);
919 String value = mMap.get(name);
920 return value != null ? Boolean.parseBoolean(value) : defaultValue;
924 * Look up the int value of a property.
926 * @param name The name of the property to look up.
927 * @param defaultValue The value to return if the property has not been defined or fails to
929 * @return the corresponding value, or defaultValue if no valid int is available.
931 public int getInt(@NonNull String name, int defaultValue) {
932 Preconditions.checkNotNull(name);
933 String value = mMap.get(name);
938 return Integer.parseInt(value);
939 } catch (NumberFormatException e) {
940 Log.e(TAG, "Parsing int failed for " + name);
946 * Look up the long value of a property.
948 * @param name The name of the property to look up.
949 * @param defaultValue The value to return if the property has not been defined. or fails to
951 * @return the corresponding value, or defaultValue if no valid long is available.
953 public long getLong(@NonNull String name, long defaultValue) {
954 Preconditions.checkNotNull(name);
955 String value = mMap.get(name);
960 return Long.parseLong(value);
961 } catch (NumberFormatException e) {
962 Log.e(TAG, "Parsing long failed for " + name);
968 * Look up the int value of a property.
970 * @param name The name of the property to look up.
971 * @param defaultValue The value to return if the property has not been defined. or fails to
972 * parse into a float.
973 * @return the corresponding value, or defaultValue if no valid float is available.
975 public float getFloat(@NonNull String name, float defaultValue) {
976 Preconditions.checkNotNull(name);
977 String value = mMap.get(name);
982 return Float.parseFloat(value);
983 } catch (NumberFormatException e) {
984 Log.e(TAG, "Parsing float failed for " + name);