| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.provider; |
| |
| import static android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG; |
| import static android.Manifest.permission.READ_DEVICE_CONFIG; |
| import static android.Manifest.permission.WRITE_DEVICE_CONFIG; |
| import static android.Manifest.permission.READ_WRITE_SYNC_DISABLED_MODE_CONFIG; |
| |
| import android.Manifest; |
| import android.annotation.CallbackExecutor; |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SuppressLint; |
| import android.annotation.SystemApi; |
| import android.content.ContentResolver; |
| import android.database.ContentObserver; |
| import android.net.Uri; |
| import android.util.ArrayMap; |
| import android.util.Log; |
| import android.util.Pair; |
| |
| import com.android.internal.annotations.GuardedBy; |
| |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.concurrent.Executor; |
| |
| /** |
| * Device level configuration parameters which can be tuned by a separate configuration service. |
| * Namespaces that end in "_native" such as {@link #NAMESPACE_NETD_NATIVE} are intended to be used |
| * by native code and should be pushed to system properties to make them accessible. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class DeviceConfig { |
| /** |
| * Namespace for all accessibility related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ACCESSIBILITY = "accessibility"; |
| |
| /** |
| * Namespace for activity manager related features. These features will be applied |
| * immediately upon change. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; |
| |
| /** |
| * Namespace for activity manager, specific to the "component alias" feature. We needed a |
| * different namespace in order to avoid phonetype from resetting it. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS = "activity_manager_ca"; |
| |
| /** |
| * Namespace for features related to auto pin confirmation. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_AUTO_PIN_CONFIRMATION = "auto_pin_confirmation"; |
| |
| /** |
| * Namespace for all activity manager related features that are used at the native level. |
| * These features are applied at reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = |
| "activity_manager_native_boot"; |
| |
| /** |
| * Namespace for AlarmManager configurations. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager"; |
| |
| /** |
| * Namespace for all app compat related features. These features will be applied |
| * immediately upon change. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_APP_COMPAT = "app_compat"; |
| |
| /** |
| * Namespace for all app hibernation related features. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_APP_HIBERNATION = "app_hibernation"; |
| |
| /** |
| * Namespace for all AppSearch related features. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_APPSEARCH = "appsearch"; |
| |
| /** |
| * Namespace for app standby configurations. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_APP_STANDBY = "app_standby"; |
| |
| /** |
| * Namespace for all App Cloning related features. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_APP_CLONING = "app_cloning"; |
| |
| /** |
| * Namespace for AttentionManagerService related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service"; |
| |
| /** |
| * Namespace for autofill feature that provides suggestions across all apps when |
| * the user interacts with input fields. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_AUTOFILL = "autofill"; |
| |
| /** |
| * Namespace for battery saver feature. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_BATTERY_SAVER = "battery_saver"; |
| |
| /** |
| * Namespace for holding battery stats configuration. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_BATTERY_STATS = "battery_stats"; |
| |
| /** |
| * Namespace for blobstore feature that allows apps to share data blobs. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_BLOBSTORE = "blobstore"; |
| |
| /** |
| * Namespace for all Bluetooth related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_BLUETOOTH = "bluetooth"; |
| |
| /** |
| * Namespace for all camera-related features that are used at the native level. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CAMERA_NATIVE = "camera_native"; |
| |
| /** |
| * Namespace for cellular security related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CELLULAR_SECURITY = "cellular_security"; |
| |
| /** |
| * Namespace for features relating to clipboard. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CLIPBOARD = "clipboard"; |
| |
| /** |
| * Namespace for all networking connectivity related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CONNECTIVITY = "connectivity"; |
| |
| /** |
| * Namespace for CaptivePortalLogin module. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CAPTIVEPORTALLOGIN = "captive_portal_login"; |
| |
| /** |
| * Namespace for all HealthFitness related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_HEALTH_FITNESS = "health_fitness"; |
| |
| /** |
| * Namespace for Tethering module. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_TETHERING = "tethering"; |
| |
| |
| /** |
| * Namespace for Nearby module. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_NEARBY = "nearby"; |
| |
| /** |
| * Namespace for content capture feature used by on-device machine intelligence |
| * to provide suggestions in a privacy-safe manner. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; |
| |
| /** |
| * Namespace for credential manager. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CREDENTIAL = "credential_manager"; |
| |
| /** |
| * Namespace for device idle configurations. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_DEVICE_IDLE = "device_idle"; |
| |
| /** |
| * Namespace for how dex runs. The feature requires a reboot to reach a clean state. |
| * |
| * @deprecated No longer used |
| * @hide |
| */ |
| @Deprecated |
| @SystemApi |
| public static final String NAMESPACE_DEX_BOOT = "dex_boot"; |
| |
| /** |
| * Namespace for display manager related features. The names to access the properties in this |
| * namespace should be defined in {@link android.hardware.display.DisplayManager}. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager"; |
| |
| /** |
| * Namespace for all Game Driver features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_GAME_DRIVER = "game_driver"; |
| |
| /** |
| * Namespace for all HDMI Control features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_HDMI_CONTROL = "hdmi_control"; |
| |
| /** |
| * Namespace for all input-related features that are used at the native level. |
| * These features are applied at reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot"; |
| |
| /** |
| * Namespace for attention-based features provided by on-device machine intelligence. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention"; |
| |
| /** |
| * Definitions for properties related to Content Suggestions. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS = |
| "intelligence_content_suggestions"; |
| |
| /** |
| * Namespace for JobScheduler configurations. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler"; |
| |
| /** |
| * Namespace for all lmkd related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native"; |
| |
| /** |
| * Namespace for all location related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_LOCATION = "location"; |
| |
| /** |
| * Namespace for all media related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_MEDIA = "media"; |
| |
| /** |
| * Namespace for all media native related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; |
| |
| /** |
| * Namespace for all Kernel Multi-Gen LRU feature. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_MGLRU_NATIVE = "mglru_native"; |
| |
| /** |
| * Namespace for all netd related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_NETD_NATIVE = "netd_native"; |
| |
| /** |
| * Namespace for all Android NNAPI related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native"; |
| |
| /** |
| * Namespace for all OnDevicePersonalization related feature. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization"; |
| |
| /** |
| * Namespace for features related to the Package Manager Service. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service"; |
| |
| /** |
| * Namespace for features related to the Profcollect native Service. |
| * These features are applied at reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot"; |
| |
| /** |
| * Namespace for features related to Reboot Readiness detection. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_REBOOT_READINESS = "reboot_readiness"; |
| |
| /** |
| * Namespace for Remote Key Provisioning related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_REMOTE_KEY_PROVISIONING_NATIVE = |
| "remote_key_provisioning_native"; |
| |
| /** |
| * Namespace for Rollback flags that are applied immediately. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ROLLBACK = "rollback"; |
| |
| /** |
| * Namespace for Rollback flags that are applied after a reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; |
| |
| /** |
| * Namespace for Rotation Resolver Manager Service. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_ROTATION_RESOLVER = "rotation_resolver"; |
| |
| /** |
| * Namespace for all runtime related features that don't require a reboot to become active. |
| * There are no feature flags using NAMESPACE_RUNTIME. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_RUNTIME = "runtime"; |
| |
| /** |
| * Namespace for all runtime related features that require system properties for accessing |
| * the feature flags from C++ or Java language code. One example is the app image startup |
| * cache feature use_app_image_startup_cache. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native"; |
| |
| /** |
| * Namespace for all runtime native boot related features. Boot in this case refers to the |
| * fact that the properties only take effect after rebooting the device. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot"; |
| |
| /** |
| * Namespace for system scheduler related features. These features will be applied |
| * immediately upon change. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SCHEDULER = "scheduler"; |
| |
| /** |
| * Namespace for all SdkSandbox related features. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SDK_SANDBOX = "sdk_sandbox"; |
| |
| /** |
| * Namespace for settings statistics features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_SETTINGS_STATS = "settings_stats"; |
| |
| /** |
| * Namespace for all statsd java features that can be applied immediately. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_STATSD_JAVA = "statsd_java"; |
| |
| /** |
| * Namespace for all statsd java features that are applied on boot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_STATSD_JAVA_BOOT = "statsd_java_boot"; |
| |
| /** |
| * Namespace for all statsd native features that can be applied immediately. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_STATSD_NATIVE = "statsd_native"; |
| |
| /** |
| * Namespace for all statsd native features that are applied on boot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot"; |
| |
| /** |
| * Namespace for storage-related features. |
| * |
| * @deprecated Replace storage namespace with storage_native_boot. |
| * @hide |
| */ |
| @Deprecated |
| @SystemApi |
| public static final String NAMESPACE_STORAGE = "storage"; |
| |
| /** |
| * Namespace for storage-related features, including native and boot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot"; |
| |
| /** |
| * Namespace for all AdServices related features. |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ADSERVICES = "adservices"; |
| |
| /** |
| * Namespace for all SurfaceFlinger features that are used at the native level. |
| * These features are applied on boot or after reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT = |
| "surface_flinger_native_boot"; |
| |
| /** |
| * Namespace for swcodec native related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native"; |
| |
| |
| /** |
| * Namespace for System UI related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SYSTEMUI = "systemui"; |
| |
| /** |
| * Namespace for system time and time zone detection related features / behavior. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SYSTEM_TIME = "system_time"; |
| |
| /** |
| * Namespace for TARE configurations. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_TARE = "tare"; |
| |
| /** |
| * Telephony related properties. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_TELEPHONY = "telephony"; |
| |
| /** |
| * Namespace for TextClassifier related features. |
| * |
| * @hide |
| * @see android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS |
| */ |
| @SystemApi |
| public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier"; |
| |
| /** |
| * Namespace for contacts provider related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider"; |
| |
| /** |
| * Namespace for settings ui related features |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_SETTINGS_UI = "settings_ui"; |
| |
| /** |
| * Namespace for android related features, i.e. for flags that affect not just a single |
| * component, but the entire system. |
| * |
| * The keys for this namespace are defined in {@link AndroidDeviceConfig}. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_ANDROID = "android"; |
| |
| /** |
| * Namespace for window manager related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_WINDOW_MANAGER = "window_manager"; |
| |
| /** |
| * Namespace for window manager features accessible by native code and |
| * loaded once per boot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot"; |
| |
| /** |
| * Definitions for selection toolbar related functions. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar"; |
| |
| /** |
| * Definitions for voice interaction related functions. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction"; |
| |
| /** |
| * Namespace for DevicePolicyManager related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_DEVICE_POLICY_MANAGER = |
| "device_policy_manager"; |
| |
| /** |
| * List of namespaces which can be read without READ_DEVICE_CONFIG permission |
| * |
| * @hide |
| */ |
| @NonNull |
| private static final List<String> PUBLIC_NAMESPACES = |
| Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA, |
| NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR, NAMESPACE_AUTOFILL, |
| NAMESPACE_DEVICE_POLICY_MANAGER, NAMESPACE_CONTENT_CAPTURE); |
| /** |
| * Privacy related properties definitions. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_PRIVACY = "privacy"; |
| |
| /** |
| * Namespace for biometrics related features |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_BIOMETRICS = "biometrics"; |
| |
| /** |
| * Permission related properties definitions. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_PERMISSIONS = "permissions"; |
| |
| /** |
| * Namespace for ota related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_OTA = "ota"; |
| |
| /** |
| * Namespace for all widget related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_WIDGET = "widget"; |
| |
| /** |
| * Namespace for connectivity thermal power manager features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER = |
| "connectivity_thermal_power_manager"; |
| |
| /** |
| * Namespace for configuration related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_CONFIGURATION = "configuration"; |
| |
| /** |
| * LatencyTracker properties definitions. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_LATENCY_TRACKER = "latency_tracker"; |
| |
| /** |
| * InteractionJankMonitor properties definitions. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| @SuppressLint("IntentName") |
| public static final String NAMESPACE_INTERACTION_JANK_MONITOR = "interaction_jank_monitor"; |
| |
| /** |
| * Namespace for game overlay related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_GAME_OVERLAY = "game_overlay"; |
| |
| /** |
| * Namespace for Android Virtualization Framework related features accessible by native code. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE = |
| "virtualization_framework_native"; |
| |
| /** |
| * Namespace for Constrain Display APIs related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis"; |
| |
| /** |
| * Namespace for App Compat Overrides related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides"; |
| |
| /** |
| * Namespace for all ultra wideband (uwb) related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_UWB = "uwb"; |
| |
| /** |
| * Namespace for AmbientContextEventManagerService related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_AMBIENT_CONTEXT_MANAGER_SERVICE = |
| "ambient_context_manager_service"; |
| |
| /** |
| * Namespace for WearableSensingManagerService related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_WEARABLE_SENSING = |
| "wearable_sensing"; |
| |
| /** |
| * Namespace for Vendor System Native related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native"; |
| |
| /** |
| * Namespace for Vendor System Native Boot related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE_BOOT = "vendor_system_native_boot"; |
| |
| /** |
| * Namespace for memory safety related features (e.g. MTE) that need a reboot to be applied |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_MEMORY_SAFETY_NATIVE_BOOT = "memory_safety_native_boot"; |
| |
| /** |
| * Namespace for memory safety related features (e.g. MTE) |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_MEMORY_SAFETY_NATIVE = "memory_safety_native"; |
| |
| /** |
| * Namespace for wear OS platform features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_WEAR = "wear"; |
| |
| /** |
| * Namespace for the input method manager platform features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_INPUT_METHOD_MANAGER = "input_method_manager"; |
| |
| /** |
| * Namespace for backup and restore service related features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_BACKUP_AND_RESTORE = "backup_and_restore"; |
| |
| /** |
| * Namespace for ARC App Compat related features. |
| * |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public static final String NAMESPACE_ARC_APP_COMPAT = "arc_app_compat"; |
| |
| /** |
| * Namespace for remote authentication features. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final String NAMESPACE_REMOTE_AUTH = "remote_auth"; |
| |
| /** |
| * The modes that can be used when disabling syncs to the 'config' settings. |
| * @hide |
| */ |
| @IntDef(prefix = "SYNC_DISABLED_MODE_", |
| value = { SYNC_DISABLED_MODE_NONE, SYNC_DISABLED_MODE_PERSISTENT, |
| SYNC_DISABLED_MODE_UNTIL_REBOOT }) |
| @Retention(RetentionPolicy.SOURCE) |
| @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) |
| public @interface SyncDisabledMode {} |
| |
| /** |
| * Sync is not disabled. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int SYNC_DISABLED_MODE_NONE = 0; |
| |
| /** |
| * Disabling of Config bulk update / syncing is persistent, i.e. it survives a device |
| * reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int SYNC_DISABLED_MODE_PERSISTENT = 1; |
| |
| /** |
| * Disabling of Config bulk update / syncing is not persistent, i.e. it will |
| * not survive a device reboot. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final int SYNC_DISABLED_MODE_UNTIL_REBOOT = 2; |
| |
| private static final Object sLock = new Object(); |
| @GuardedBy("sLock") |
| private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners = |
| new ArrayMap<>(); |
| @GuardedBy("sLock") |
| private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>(); |
| private static final String TAG = "DeviceConfig"; |
| |
| /** |
| * Interface for monitoring callback functions. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public interface MonitorCallback { |
| /** |
| * Callback for updating a namespace. |
| * Reports that a config in the given namespace has changed. |
| * Isn't called for {@link DeviceConfig#getPublicNamespaces() public namespaces}. |
| * |
| * @param updatedNamespace the namespace, within which at least one config has changed. |
| * @hide |
| */ |
| @SystemApi |
| void onNamespaceUpdate(@NonNull String updatedNamespace); |
| |
| /** |
| * Callback for accessing device config. |
| * Reports an access to a the given namespace and the given calling package. |
| * Isn't called for {@link DeviceConfig#getPublicNamespaces() public namespaces}. |
| * |
| * @param callingPackage the calling package id. |
| * @param namespace the namespace, within which one of its config has been accessed. |
| * @hide |
| */ |
| @SystemApi |
| void onDeviceConfigAccess(@NonNull String callingPackage, @NonNull String namespace); |
| } |
| |
| // Should never be invoked |
| private DeviceConfig() { |
| } |
| |
| /** |
| * Look up the value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @return the corresponding value, or null if not present. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| @Nullable |
| public static String getProperty(@NonNull String namespace, @NonNull String name) { |
| // Fetch all properties for the namespace at once and cache them in the local process, so we |
| // incur the cost of the IPC less often. Lookups happen much more frequently than updates, |
| // and we want to optimize the former. |
| return getProperties(namespace, name).getString(name, null); |
| } |
| |
| /** |
| * Look up the values of multiple properties for a particular namespace. The lookup is atomic, |
| * such that the values of these properties cannot change between the time when the first is |
| * fetched and the time when the last is fetched. |
| * <p> |
| * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none |
| * or all of the change is picked up here, but never only part of it. |
| * |
| * @param namespace The namespace containing the properties to look up. |
| * @param names The names of properties to look up, or empty to fetch all properties for the |
| * given namespace. |
| * @return {@link Properties} object containing the requested properties. This reflects the |
| * state of these properties at the time of the lookup, and is not updated to reflect any |
| * future changes. The keyset of this Properties object will contain only the intersection |
| * of properties already set and properties requested via the names parameter. Properties |
| * that are already set but were not requested will not be contained here. Properties that |
| * are not set, but were requested will not be contained here either. |
| * @hide |
| */ |
| @SystemApi |
| @NonNull |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) { |
| return new Properties(namespace, |
| Settings.Config.getStrings(namespace, Arrays.asList(names))); |
| } |
| |
| /** |
| * Look up the String value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property does not exist or has no non-null |
| * value. |
| * @return the corresponding value, or defaultValue if none exists. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| @Nullable |
| public static String getString(@NonNull String namespace, @NonNull String name, |
| @Nullable String defaultValue) { |
| String value = getProperty(namespace, name); |
| return value != null ? value : defaultValue; |
| } |
| |
| /** |
| * Look up the boolean value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property does not exist or has no non-null |
| * value. |
| * @return the corresponding value, or defaultValue if none exists. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| public static boolean getBoolean(@NonNull String namespace, @NonNull String name, |
| boolean defaultValue) { |
| String value = getProperty(namespace, name); |
| return value != null ? Boolean.parseBoolean(value) : defaultValue; |
| } |
| |
| /** |
| * Look up the int value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property does not exist, has no non-null |
| * value, or fails to parse into an int. |
| * @return the corresponding value, or defaultValue if either none exists or it does not parse. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) { |
| String value = getProperty(namespace, name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Integer.parseInt(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Look up the long value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property does not exist, has no non-null |
| * value, or fails to parse into a long. |
| * @return the corresponding value, or defaultValue if either none exists or it does not parse. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) { |
| String value = getProperty(namespace, name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Long.parseLong(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing long failed for " + namespace + ":" + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Look up the float value of a property for a particular namespace. |
| * |
| * @param namespace The namespace containing the property to look up. |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property does not exist, has no non-null |
| * value, or fails to parse into a float. |
| * @return the corresponding value, or defaultValue if either none exists or it does not parse. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(READ_DEVICE_CONFIG) |
| public static float getFloat(@NonNull String namespace, @NonNull String name, |
| float defaultValue) { |
| String value = getProperty(namespace, name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Float.parseFloat(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing float failed for " + namespace + ":" + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Create a new property with the provided name and value in the provided namespace, or |
| * update the value of such a property if it already exists. The same name can exist in multiple |
| * namespaces and might have different values in any or all namespaces. |
| * <p> |
| * The method takes an argument indicating whether to make the value the default for this |
| * property. |
| * <p> |
| * All properties stored for a particular scope can be reverted to their default values |
| * by passing the namespace to {@link #resetToDefaults(int, String)}. |
| * |
| * @param namespace The namespace containing the property to create or update. |
| * @param name The name of the property to create or update. |
| * @param value The value to store for the property. |
| * @param makeDefault Whether to make the new value the default one. |
| * @return {@code true} if the value was set, {@code false} if the storage implementation throws |
| * errors. |
| * @hide |
| * @see #resetToDefaults(int, String). |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG}) |
| public static boolean setProperty(@NonNull String namespace, @NonNull String name, |
| @Nullable String value, boolean makeDefault) { |
| return Settings.Config.putString(namespace, name, value, makeDefault); |
| } |
| |
| /** |
| * Set all of the properties for a specific namespace. Pre-existing properties will be updated |
| * and new properties will be added if necessary. Any pre-existing properties for the specific |
| * namespace which are not part of the provided {@link Properties} object will be deleted from |
| * the namespace. These changes are all applied atomically, such that no calls to read or reset |
| * these properties can happen in the middle of this update. |
| * <p> |
| * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either |
| * none or all of this update is picked up, but never only part of it. |
| * |
| * @param properties the complete set of properties to set for a specific namespace. |
| * @throws BadConfigException if the provided properties are banned by RescueParty. |
| * @return {@code true} if the values were set, {@code false} otherwise. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG}) |
| public static boolean setProperties(@NonNull Properties properties) throws BadConfigException { |
| return Settings.Config.setStrings(properties.getNamespace(), |
| properties.mMap); |
| } |
| |
| /** |
| * Delete a property with the provided name and value in the provided namespace |
| * |
| * @param namespace The namespace containing the property to delete. |
| * @param name The name of the property to delete. |
| * @return {@code true} if the property was deleted or it did not exist in the first place. |
| * Return {@code false} if the storage implementation throws errors. |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG}) |
| public static boolean deleteProperty(@NonNull String namespace, @NonNull String name) { |
| return Settings.Config.deleteString(namespace, name); |
| } |
| |
| /** |
| * Reset properties to their default values by removing the underlying values. |
| * <p> |
| * The method accepts an optional namespace parameter. If provided, only properties set within |
| * that namespace will be reset. Otherwise, all properties will be reset. |
| * <p> |
| * Note: This method should only be used by {@link com.android.server.RescueParty}. It was |
| * designed to be used in the event of boot or crash loops caused by flag changes. It does not |
| * revert flag values to defaults - instead it removes the property entirely which causes the |
| * consumer of the flag to use hardcoded defaults upon retrieval. |
| * <p> |
| * To clear values for a namespace without removing the underlying properties, construct a |
| * {@link Properties} object with the caller's namespace and either an empty flag map, or some |
| * snapshot of flag values. Then use {@link #setProperties(Properties)} to remove all flags |
| * under the namespace, or set them to the values in the snapshot. |
| * <p> |
| * To revert values for testing, one should mock DeviceConfig using |
| * {@link com.android.server.testables.TestableDeviceConfig} where possible. Otherwise, fallback |
| * to using {@link #setProperties(Properties)} as outlined above. |
| * |
| * @param resetMode The reset mode to use. |
| * @param namespace Optionally, the specific namespace which resets will be limited to. |
| * @hide |
| * @see #setProperty(String, String, String, boolean) |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG}) |
| public static void resetToDefaults(int resetMode, @Nullable String namespace) { |
| Settings.Config.resetToDefaults(resetMode, namespace); |
| } |
| |
| /** |
| * Disables or re-enables bulk modifications ({@link #setProperties(Properties)}) to device |
| * config values. This is intended for use during tests to prevent a sync operation clearing |
| * config values which could influence the outcome of the tests, i.e. by changing behavior. |
| * |
| * @param syncDisabledMode the mode to use, see {@link #SYNC_DISABLED_MODE_NONE}, |
| * {@link #SYNC_DISABLED_MODE_PERSISTENT} and {@link #SYNC_DISABLED_MODE_UNTIL_REBOOT} |
| * |
| * @see #getSyncDisabledMode() |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG}) |
| public static void setSyncDisabledMode(@SyncDisabledMode int syncDisabledMode) { |
| Settings.Config.setSyncDisabledMode(syncDisabledMode); |
| } |
| |
| /** |
| * Returns the current mode of sync disabling. |
| * |
| * @see #setSyncDisabledMode(int) |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(anyOf = {WRITE_DEVICE_CONFIG, READ_WRITE_SYNC_DISABLED_MODE_CONFIG}) |
| public static int getSyncDisabledMode() { |
| return Settings.Config.getSyncDisabledMode(); |
| } |
| |
| /** |
| * Add a listener for property changes. |
| * <p> |
| * This listener will be called whenever properties in the specified namespace change. Callbacks |
| * will be made on the specified executor. Future calls to this method with the same listener |
| * will replace the old namespace and executor. Remove the listener entirely by calling |
| * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}. |
| * |
| * @param namespace The namespace containing properties to monitor. |
| * @param executor The executor which will be used to run callbacks. |
| * @param onPropertiesChangedListener The listener to add. |
| * @hide |
| * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener) |
| */ |
| @SystemApi |
| public static void addOnPropertiesChangedListener( |
| @NonNull String namespace, |
| @NonNull @CallbackExecutor Executor executor, |
| @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { |
| synchronized (sLock) { |
| Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener); |
| if (oldNamespace == null) { |
| // Brand new listener, add it to the list. |
| sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); |
| incrementNamespace(namespace); |
| } else if (namespace.equals(oldNamespace.first)) { |
| // Listener is already registered for this namespace, update executor just in case. |
| sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); |
| } else { |
| // Update this listener from an old namespace to the new one. |
| decrementNamespace(sListeners.get(onPropertiesChangedListener).first); |
| sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor)); |
| incrementNamespace(namespace); |
| } |
| } |
| } |
| |
| /** |
| * Remove a listener for property changes. The listener will receive no further notification of |
| * property changes. |
| * |
| * @param onPropertiesChangedListener The listener to remove. |
| * @hide |
| * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener) |
| */ |
| @SystemApi |
| public static void removeOnPropertiesChangedListener( |
| @NonNull OnPropertiesChangedListener onPropertiesChangedListener) { |
| Objects.requireNonNull(onPropertiesChangedListener); |
| synchronized (sLock) { |
| if (sListeners.containsKey(onPropertiesChangedListener)) { |
| decrementNamespace(sListeners.get(onPropertiesChangedListener).first); |
| sListeners.remove(onPropertiesChangedListener); |
| } |
| } |
| } |
| |
| /** |
| * Setter callback for monitoring Config table. |
| * |
| * @param executor the {@link Executor} on which to invoke the callback |
| * @param callback callback to set |
| * |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) |
| public static void setMonitorCallback( |
| @NonNull ContentResolver resolver, |
| @NonNull @CallbackExecutor Executor executor, |
| @NonNull MonitorCallback callback) { |
| Settings.Config.setMonitorCallback(resolver, executor, callback); |
| } |
| |
| /** |
| * Clear callback for monitoring Config table. |
| * this may only be used to clear callback function registered by |
| * {@link DeviceConfig#setMonitorCallback} |
| * @hide |
| */ |
| @SystemApi |
| @RequiresPermission(Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) |
| public static void clearMonitorCallback(@NonNull ContentResolver resolver) { |
| Settings.Config.clearMonitorCallback(resolver); |
| } |
| |
| /** |
| * Increment the count used to represent the number of listeners subscribed to the given |
| * namespace. If this is the first (i.e. incrementing from 0 to 1) for the given namespace, a |
| * ContentObserver is registered. |
| * |
| * @param namespace The namespace to increment the count for. |
| */ |
| @GuardedBy("sLock") |
| private static void incrementNamespace(@NonNull String namespace) { |
| Objects.requireNonNull(namespace); |
| Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace); |
| if (namespaceCount != null) { |
| sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1)); |
| } else { |
| // This is a new namespace, register a ContentObserver for it. |
| ContentObserver contentObserver = new ContentObserver(null) { |
| @Override |
| public void onChange(boolean selfChange, Uri uri) { |
| if (uri != null) { |
| handleChange(uri); |
| } |
| } |
| }; |
| Settings.Config |
| .registerContentObserver(namespace, true, contentObserver); |
| sNamespaces.put(namespace, new Pair<>(contentObserver, 1)); |
| } |
| } |
| |
| /** |
| * Decrement the count used to represent the number of listeners subscribed to the given |
| * namespace. If this is the final decrement call (i.e. decrementing from 1 to 0) for the given |
| * namespace, the ContentObserver that had been tracking it will be removed. |
| * |
| * @param namespace The namespace to decrement the count for. |
| */ |
| @GuardedBy("sLock") |
| private static void decrementNamespace(@NonNull String namespace) { |
| Objects.requireNonNull(namespace); |
| Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace); |
| if (namespaceCount == null) { |
| // This namespace is not registered and does not need to be decremented |
| return; |
| } else if (namespaceCount.second > 1) { |
| sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second - 1)); |
| } else { |
| // Decrementing a namespace to zero means we no longer need its ContentObserver. |
| Settings.Config.unregisterContentObserver(namespaceCount.first); |
| sNamespaces.remove(namespace); |
| } |
| } |
| |
| private static void handleChange(@NonNull Uri uri) { |
| Objects.requireNonNull(uri); |
| List<String> pathSegments = uri.getPathSegments(); |
| // pathSegments(0) is "config" |
| final String namespace = pathSegments.get(1); |
| Properties.Builder propBuilder = new Properties.Builder(namespace); |
| try { |
| Properties allProperties = getProperties(namespace); |
| for (int i = 2; i < pathSegments.size(); ++i) { |
| String key = pathSegments.get(i); |
| propBuilder.setString(key, allProperties.getString(key, null)); |
| } |
| } catch (SecurityException e) { |
| // Silently failing to not crash binder or listener threads. |
| Log.e(TAG, "OnPropertyChangedListener update failed: permission violation."); |
| return; |
| } |
| Properties properties = propBuilder.build(); |
| |
| synchronized (sLock) { |
| for (int i = 0; i < sListeners.size(); i++) { |
| if (namespace.equals(sListeners.valueAt(i).first)) { |
| final OnPropertiesChangedListener listener = sListeners.keyAt(i); |
| sListeners.valueAt(i).second.execute(() -> { |
| listener.onPropertiesChanged(properties); |
| }); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns list of namespaces that can be read without READ_DEVICE_CONFIG_PERMISSION; |
| * @hide |
| */ |
| @SystemApi |
| public static @NonNull List<String> getPublicNamespaces() { |
| return PUBLIC_NAMESPACES; |
| } |
| |
| /** |
| * Returns list of flags that can be written with adb as non-root. |
| * @hide |
| */ |
| @SystemApi |
| public static @NonNull Set<String> getAdbWritableFlags() { |
| return WritableFlags.ALLOWLIST; |
| } |
| |
| /** |
| * Interface for monitoring changes to properties. Implementations will receive callbacks when |
| * properties change, including a {@link Properties} object which contains a single namespace |
| * and all of the properties which changed for that namespace. This includes properties which |
| * were added, updated, or deleted. This is not necessarily a complete list of all properties |
| * belonging to the namespace, as properties which don't change are omitted. |
| * <p> |
| * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public interface OnPropertiesChangedListener { |
| /** |
| * Called when one or more properties have changed, providing a Properties object with all |
| * of the changed properties. This object will contain only properties which have changed, |
| * not the complete set of all properties belonging to the namespace. |
| * |
| * @param properties Contains the complete collection of properties which have changed for a |
| * single namespace. This includes only those which were added, updated, |
| * or deleted. |
| */ |
| void onPropertiesChanged(@NonNull Properties properties); |
| } |
| |
| /** |
| * Thrown by {@link #setProperties(Properties)} when a configuration is rejected. This |
| * happens if RescueParty has identified a bad configuration and reset the namespace. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static class BadConfigException extends Exception {} |
| |
| /** |
| * A mapping of properties to values, as well as a single namespace which they all belong to. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static class Properties { |
| private final String mNamespace; |
| private final HashMap<String, String> mMap; |
| private Set<String> mKeyset; |
| |
| /** |
| * Create a mapping of properties to values and the namespace they belong to. |
| * |
| * @param namespace The namespace these properties belong to. |
| * @param keyValueMap A map between property names and property values. |
| * @hide |
| */ |
| @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) |
| public Properties(@NonNull String namespace, @Nullable Map<String, String> keyValueMap) { |
| Objects.requireNonNull(namespace); |
| mNamespace = namespace; |
| mMap = new HashMap(); |
| if (keyValueMap != null) { |
| mMap.putAll(keyValueMap); |
| } |
| } |
| |
| /** |
| * @return the namespace all properties within this instance belong to. |
| */ |
| @NonNull |
| public String getNamespace() { |
| return mNamespace; |
| } |
| |
| /** |
| * @return the non-null set of property names. |
| */ |
| @NonNull |
| public Set<String> getKeyset() { |
| if (mKeyset == null) { |
| mKeyset = Collections.unmodifiableSet(mMap.keySet()); |
| } |
| return mKeyset; |
| } |
| |
| /** |
| * Look up the String value of a property. |
| * |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property has not been defined. |
| * @return the corresponding value, or defaultValue if none exists. |
| */ |
| @Nullable |
| public String getString(@NonNull String name, @Nullable String defaultValue) { |
| Objects.requireNonNull(name); |
| String value = mMap.get(name); |
| return value != null ? value : defaultValue; |
| } |
| |
| /** |
| * Look up the boolean value of a property. |
| * |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property has not been defined. |
| * @return the corresponding value, or defaultValue if none exists. |
| */ |
| public boolean getBoolean(@NonNull String name, boolean defaultValue) { |
| Objects.requireNonNull(name); |
| String value = mMap.get(name); |
| return value != null ? Boolean.parseBoolean(value) : defaultValue; |
| } |
| |
| /** |
| * Look up the int value of a property. |
| * |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property has not been defined or fails to |
| * parse into an int. |
| * @return the corresponding value, or defaultValue if no valid int is available. |
| */ |
| public int getInt(@NonNull String name, int defaultValue) { |
| Objects.requireNonNull(name); |
| String value = mMap.get(name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Integer.parseInt(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing int failed for " + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Look up the long value of a property. |
| * |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property has not been defined. or fails to |
| * parse into a long. |
| * @return the corresponding value, or defaultValue if no valid long is available. |
| */ |
| public long getLong(@NonNull String name, long defaultValue) { |
| Objects.requireNonNull(name); |
| String value = mMap.get(name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Long.parseLong(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing long failed for " + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Look up the int value of a property. |
| * |
| * @param name The name of the property to look up. |
| * @param defaultValue The value to return if the property has not been defined. or fails to |
| * parse into a float. |
| * @return the corresponding value, or defaultValue if no valid float is available. |
| */ |
| public float getFloat(@NonNull String name, float defaultValue) { |
| Objects.requireNonNull(name); |
| String value = mMap.get(name); |
| if (value == null) { |
| return defaultValue; |
| } |
| try { |
| return Float.parseFloat(value); |
| } catch (NumberFormatException e) { |
| Log.e(TAG, "Parsing float failed for " + name); |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Builder class for the construction of {@link Properties} objects. |
| */ |
| public static final class Builder { |
| @NonNull |
| private final String mNamespace; |
| @NonNull |
| private final Map<String, String> mKeyValues = new HashMap<>(); |
| |
| /** |
| * Create a new Builders for the specified namespace. |
| * @param namespace non null namespace. |
| */ |
| public Builder(@NonNull String namespace) { |
| mNamespace = namespace; |
| } |
| |
| /** |
| * Add a new property with the specified key and value. |
| * @param name non null name of the property. |
| * @param value nullable string value of the property. |
| * @return this Builder object |
| */ |
| @NonNull |
| public Builder setString(@NonNull String name, @Nullable String value) { |
| mKeyValues.put(name, value); |
| return this; |
| } |
| |
| /** |
| * Add a new property with the specified key and value. |
| * @param name non null name of the property. |
| * @param value nullable string value of the property. |
| * @return this Builder object |
| */ |
| @NonNull |
| public Builder setBoolean(@NonNull String name, boolean value) { |
| mKeyValues.put(name, Boolean.toString(value)); |
| return this; |
| } |
| |
| /** |
| * Add a new property with the specified key and value. |
| * @param name non null name of the property. |
| * @param value int value of the property. |
| * @return this Builder object |
| */ |
| @NonNull |
| public Builder setInt(@NonNull String name, int value) { |
| mKeyValues.put(name, Integer.toString(value)); |
| return this; |
| } |
| |
| /** |
| * Add a new property with the specified key and value. |
| * @param name non null name of the property. |
| * @param value long value of the property. |
| * @return this Builder object |
| */ |
| @NonNull |
| public Builder setLong(@NonNull String name, long value) { |
| mKeyValues.put(name, Long.toString(value)); |
| return this; |
| } |
| |
| /** |
| * Add a new property with the specified key and value. |
| * @param name non null name of the property. |
| * @param value float value of the property. |
| * @return this Builder object |
| */ |
| @NonNull |
| public Builder setFloat(@NonNull String name, float value) { |
| mKeyValues.put(name, Float.toString(value)); |
| return this; |
| } |
| |
| /** |
| * Create a new {@link Properties} object. |
| * @return non null Properties. |
| */ |
| @NonNull |
| public Properties build() { |
| return new Properties(mNamespace, mKeyValues); |
| } |
| } |
| } |
| |
| } |