diff --git a/api/current.txt b/api/current.txt index ee21360c490bc..0f5fd35547577 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18718,6 +18718,53 @@ package android.provider { field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id"; } + public static final class Settings.Global extends android.provider.Settings.NameValueTable { + ctor public Settings.Global(); + method public static float getFloat(android.content.ContentResolver, java.lang.String, float); + method public static float getFloat(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; + method public static int getInt(android.content.ContentResolver, java.lang.String, int); + method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; + method public static long getLong(android.content.ContentResolver, java.lang.String, long); + method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; + method public static synchronized java.lang.String getString(android.content.ContentResolver, java.lang.String); + method public static android.net.Uri getUriFor(java.lang.String); + method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float); + method public static boolean putInt(android.content.ContentResolver, java.lang.String, int); + method public static boolean putLong(android.content.ContentResolver, java.lang.String, long); + method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String); + field public static final java.lang.String ADB_ENABLED = "adb_enabled"; + field public static final java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on"; + field public static final java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; + field public static final java.lang.String AUTO_TIME = "auto_time"; + field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; + field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on"; + field public static final android.net.Uri CONTENT_URI; + field public static final java.lang.String DATA_ROAMING = "data_roaming"; + field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; + field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned"; + field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + field public static final java.lang.String NETWORK_PREFERENCE = "network_preference"; + field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth"; + field public static final java.lang.String RADIO_CELL = "cell"; + field public static final java.lang.String RADIO_NFC = "nfc"; + field public static final java.lang.String RADIO_WIFI = "wifi"; + field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; + field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_global_version"; + field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; + field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail"; + field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms"; + field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"; + field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay"; + field public static final java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"; + field public static final java.lang.String WIFI_ON = "wifi_on"; + field public static final java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy"; + field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0 + field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2 + field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1 + field public static final java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; + } + public static class Settings.NameValueTable implements android.provider.BaseColumns { ctor public Settings.NameValueTable(); method public static android.net.Uri getUriFor(android.net.Uri, java.lang.String); @@ -18744,28 +18791,28 @@ package android.provider { method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean); field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled"; field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; - field public static final java.lang.String ADB_ENABLED = "adb_enabled"; + field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled"; field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins"; field public static final java.lang.String ALLOW_MOCK_LOCATION = "mock_location"; field public static final java.lang.String ANDROID_ID = "android_id"; field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data"; - field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on"; + field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String DATA_ROAMING = "data_roaming"; + field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming"; field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method"; - field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; - field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned"; + field public static final deprecated java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; + field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned"; field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services"; field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods"; field public static final java.lang.String HTTP_PROXY = "http_proxy"; field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility"; - field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field public static final java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; field public static final java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; field public static final java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled"; field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"; field public static final deprecated java.lang.String LOGGING_ID = "logging_id"; - field public static final java.lang.String NETWORK_PREFERENCE = "network_preference"; + field public static final deprecated java.lang.String NETWORK_PREFERENCE = "network_preference"; field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled"; field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"; field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; @@ -18781,9 +18828,9 @@ package android.provider { field public static final deprecated java.lang.String TTS_DEFAULT_VARIANT = "tts_default_variant"; field public static final java.lang.String TTS_ENABLED_PLUGINS = "tts_enabled_plugins"; field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults"; - field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; - field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail"; - field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; + field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail"; + field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms"; field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"; field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay"; @@ -18816,7 +18863,7 @@ package android.provider { method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; method public static long getLong(android.content.ContentResolver, java.lang.String, long); method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException; - method public static boolean getShowGTalkServiceStatus(android.content.ContentResolver); + method public static deprecated boolean getShowGTalkServiceStatus(android.content.ContentResolver); method public static synchronized java.lang.String getString(android.content.ContentResolver, java.lang.String); method public static android.net.Uri getUriFor(java.lang.String); method public static boolean putConfiguration(android.content.ContentResolver, android.content.res.Configuration); @@ -18824,18 +18871,18 @@ package android.provider { method public static boolean putInt(android.content.ContentResolver, java.lang.String, int); method public static boolean putLong(android.content.ContentResolver, java.lang.String, long); method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String); - method public static void setShowGTalkServiceStatus(android.content.ContentResolver, boolean); + method public static deprecated void setShowGTalkServiceStatus(android.content.ContentResolver, boolean); field public static final java.lang.String ACCELEROMETER_ROTATION = "accelerometer_rotation"; field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled"; - field public static final java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on"; - field public static final java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; + field public static final deprecated java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on"; + field public static final deprecated java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; field public static final java.lang.String ALARM_ALERT = "alarm_alert"; field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities"; field public static final deprecated java.lang.String ANDROID_ID = "android_id"; field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale"; field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible"; - field public static final java.lang.String AUTO_TIME = "auto_time"; - field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; + field public static final deprecated java.lang.String AUTO_TIME = "auto_time"; + field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone"; field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability"; field public static final java.lang.String BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout"; field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on"; @@ -18868,10 +18915,10 @@ package android.provider { field public static final deprecated java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled"; field public static final deprecated java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"; field public static final deprecated java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; - field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth"; - field public static final java.lang.String RADIO_CELL = "cell"; - field public static final java.lang.String RADIO_NFC = "nfc"; - field public static final java.lang.String RADIO_WIFI = "wifi"; + field public static final deprecated java.lang.String RADIO_BLUETOOTH = "bluetooth"; + field public static final deprecated java.lang.String RADIO_CELL = "cell"; + field public static final deprecated java.lang.String RADIO_NFC = "nfc"; + field public static final deprecated java.lang.String RADIO_WIFI = "wifi"; field public static final java.lang.String RINGTONE = "ringtone"; field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness"; field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode"; @@ -18884,7 +18931,7 @@ package android.provider { field public static final java.lang.String SHOW_PROCESSES = "show_processes"; field public static final deprecated java.lang.String SHOW_WEB_SUGGESTIONS = "show_web_suggestions"; field public static final java.lang.String SOUND_EFFECTS_ENABLED = "sound_effects_enabled"; - field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; + field public static final deprecated java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_system_version"; field public static final java.lang.String TEXT_AUTO_CAPS = "auto_caps"; field public static final java.lang.String TEXT_AUTO_PUNCTUATE = "auto_punctuate"; @@ -18912,10 +18959,10 @@ package android.provider { field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay"; field public static final deprecated java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"; field public static final deprecated java.lang.String WIFI_ON = "wifi_on"; - field public static final java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy"; - field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0 - field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2 - field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1 + field public static final deprecated java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy"; + field public static final deprecated int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0 + field public static final deprecated int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2 + field public static final deprecated int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1 field public static final java.lang.String WIFI_STATIC_DNS1 = "wifi_static_dns1"; field public static final java.lang.String WIFI_STATIC_DNS2 = "wifi_static_dns2"; field public static final java.lang.String WIFI_STATIC_GATEWAY = "wifi_static_gateway"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1b0c7753e6b0d..6b4bc76826da4 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -620,6 +620,25 @@ public final class Settings { */ public static final String CALL_METHOD_GET_SECURE = "GET_secure"; + /** + * @hide - Private call() method on SettingsProvider to read from 'global' table. + */ + public static final String CALL_METHOD_GET_GLOBAL = "GET_global"; + + /** + * @hide - User handle argument extra to the fast-path call()-based requests + */ + public static final String CALL_METHOD_USER_KEY = "_user"; + + /** @hide - Private call() method to write to 'system' table */ + public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system"; + + /** @hide - Private call() method to write to 'secure' table */ + public static final String CALL_METHOD_PUT_SECURE = "PUT_secure"; + + /** @hide - Private call() method to write to 'global' table */ + public static final String CALL_METHOD_PUT_GLOBAL= "PUT_global"; + /** * Activity Extra: Limit available options in launched activity based on the given authority. *

@@ -640,7 +659,7 @@ public final class Settings { public static final String AUTHORITY = "settings"; private static final String TAG = "Settings"; - private static final boolean LOCAL_LOGV = false || false; + private static final boolean LOCAL_LOGV = false; public static class SettingNotFoundException extends AndroidException { public SettingNotFoundException(String msg) { @@ -693,20 +712,52 @@ public final class Settings { // The method we'll call (or null, to not use) on the provider // for the fast path of retrieving settings. - private final String mCallCommand; + private final String mCallGetCommand; + private final String mCallSetCommand; - public NameValueCache(String versionSystemProperty, Uri uri, String callCommand) { + public NameValueCache(String versionSystemProperty, Uri uri, + String getCommand, String setCommand) { mVersionSystemProperty = versionSystemProperty; mUri = uri; - mCallCommand = callCommand; + mCallGetCommand = getCommand; + mCallSetCommand = setCommand; } - public String getString(ContentResolver cr, String name) { + private IContentProvider lazyGetProvider(ContentResolver cr) { + IContentProvider cp = null; + synchronized (this) { + cp = mContentProvider; + if (cp == null) { + cp = mContentProvider = cr.acquireProvider(mUri.getAuthority()); + } + } + return cp; + } + + public boolean putStringForUser(ContentResolver cr, String name, String value, + final int userHandle) { + try { + Bundle arg = new Bundle(); + arg.putString(Settings.NameValueTable.VALUE, value); + IContentProvider cp = lazyGetProvider(cr); + cp.call(mCallSetCommand, name, arg); + } catch (RemoteException e) { + Log.w(TAG, "Can't set key " + name + " in " + mUri, e); + return false; + } + return true; + } + + public boolean putString(ContentResolver cr, String name, String value) { + return putStringForUser(cr, name, value, UserHandle.myUserId()); + } + + public String getStringForUser(ContentResolver cr, String name, final int userHandle) { long newValuesVersion = SystemProperties.getLong(mVersionSystemProperty, 0); synchronized (this) { if (mValuesVersion != newValuesVersion) { - if (LOCAL_LOGV) { + if (LOCAL_LOGV || false) { Log.v(TAG, "invalidate [" + mUri.getLastPathSegment() + "]: current " + newValuesVersion + " != cached " + mValuesVersion); } @@ -720,21 +771,20 @@ public final class Settings { } } - IContentProvider cp = null; - synchronized (this) { - cp = mContentProvider; - if (cp == null) { - cp = mContentProvider = cr.acquireProvider(mUri.getAuthority()); - } - } + IContentProvider cp = lazyGetProvider(cr); // Try the fast path first, not using query(). If this // fails (alternate Settings provider that doesn't support // this interface?) then we fall back to the query/table // interface. - if (mCallCommand != null) { + if (mCallGetCommand != null) { try { - Bundle b = cp.call(mCallCommand, name, null); + Bundle args = null; + if (userHandle != UserHandle.myUserId()) { + args = new Bundle(); + args.putInt(CALL_METHOD_USER_KEY, userHandle); + } + Bundle b = cp.call(mCallGetCommand, name, args); if (b != null) { String value = b.getPairValue(); synchronized (this) { @@ -775,6 +825,10 @@ public final class Settings { if (c != null) c.close(); } } + + public String getString(ContentResolver cr, String name) { + return getStringForUser(cr, name, UserHandle.myUserId()); + } } /** @@ -791,13 +845,8 @@ public final class Settings { private static final HashSet MOVED_TO_SECURE; static { MOVED_TO_SECURE = new HashSet(30); - MOVED_TO_SECURE.add(Secure.ADB_ENABLED); MOVED_TO_SECURE.add(Secure.ANDROID_ID); - MOVED_TO_SECURE.add(Secure.BLUETOOTH_ON); - MOVED_TO_SECURE.add(Secure.DATA_ROAMING); - MOVED_TO_SECURE.add(Secure.DEVICE_PROVISIONED); MOVED_TO_SECURE.add(Secure.HTTP_PROXY); - MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS); MOVED_TO_SECURE.add(Secure.LOCATION_PROVIDERS_ALLOWED); MOVED_TO_SECURE.add(Secure.LOCK_BIOMETRIC_WEAK_FLAGS); MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_ENABLED); @@ -808,7 +857,6 @@ public final class Settings { MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE); MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_REDIRECT_URL); MOVED_TO_SECURE.add(Secure.SETTINGS_CLASSNAME); - MOVED_TO_SECURE.add(Secure.USB_MASS_STORAGE_ENABLED); MOVED_TO_SECURE.add(Secure.USE_GOOGLE_MAIL); MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY); @@ -827,6 +875,44 @@ public final class Settings { MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS); } + private static final HashSet MOVED_TO_GLOBAL; + static { + MOVED_TO_GLOBAL = new HashSet(); + MOVED_TO_GLOBAL.add(Global.ADB_ENABLED); + MOVED_TO_GLOBAL.add(Global.BLUETOOTH_ON); + MOVED_TO_GLOBAL.add(Global.DATA_ROAMING); + MOVED_TO_GLOBAL.add(Global.DEVICE_PROVISIONED); + MOVED_TO_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS); + MOVED_TO_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED); + + MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_ON); + MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_RADIOS); + MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); + MOVED_TO_GLOBAL.add(Settings.Global.AUTO_TIME); + MOVED_TO_GLOBAL.add(Settings.Global.AUTO_TIME_ZONE); + MOVED_TO_GLOBAL.add(Settings.Global.CAR_DOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.CAR_UNDOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.DESK_DOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.DESK_UNDOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.DOCK_SOUNDS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.LOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.UNLOCK_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.LOW_BATTERY_SOUND); + MOVED_TO_GLOBAL.add(Settings.Global.POWER_SOUNDS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SLEEP_POLICY); + } + + private static void lazyInitCache() { + if (sNameValueCache == null) { + sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(), + CONTENT_URI, + CALL_METHOD_GET_SYSTEM, + CALL_METHOD_PUT_SYSTEM); + } + } + /** * Look up a name in the database. * @param resolver to access the database with @@ -834,16 +920,24 @@ public final class Settings { * @return the corresponding value, or null if not present */ public synchronized static String getString(ContentResolver resolver, String name) { + return getStringForUser(resolver, name, UserHandle.myUserId()); + } + + /** @hide */ + public synchronized static String getStringForUser(ContentResolver resolver, String name, + int userHandle) { if (MOVED_TO_SECURE.contains(name)) { Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + " to android.provider.Settings.Secure, returning read-only value."); - return Secure.getString(resolver, name); + return Secure.getStringForUser(resolver, name, userHandle); } - if (sNameValueCache == null) { - sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI, - CALL_METHOD_GET_SYSTEM); + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Global, returning read-only value."); + return Global.getStringForUser(resolver, name, userHandle); } - return sNameValueCache.getString(resolver, name); + lazyInitCache(); + return sNameValueCache.getStringForUser(resolver, name, userHandle); } /** @@ -854,12 +948,24 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putString(ContentResolver resolver, String name, String value) { + return putStringForUser(resolver, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putStringForUser(ContentResolver resolver, String name, String value, + int userHandle) { if (MOVED_TO_SECURE.contains(name)) { Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + " to android.provider.Settings.Secure, value is unchanged."); return false; } - return putString(resolver, CONTENT_URI, name, value); + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Global, value is unchanged."); + return false; + } + lazyInitCache(); + return sNameValueCache.putStringForUser(resolver, name, value, userHandle); } /** @@ -874,6 +980,11 @@ public final class Settings { + " to android.provider.Settings.Secure, returning Secure URI."); return Secure.getUriFor(Secure.CONTENT_URI, name); } + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Global, returning read-only global URI."); + return Global.getUriFor(Global.CONTENT_URI, name); + } return getUriFor(CONTENT_URI, name); } @@ -892,7 +1003,12 @@ public final class Settings { * or not a valid integer. */ public static int getInt(ContentResolver cr, String name, int def) { - String v = getString(cr, name); + return getIntForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) { + String v = getStringForUser(cr, name, userHandle); try { return v != null ? Integer.parseInt(v) : def; } catch (NumberFormatException e) { @@ -920,7 +1036,13 @@ public final class Settings { */ public static int getInt(ContentResolver cr, String name) throws SettingNotFoundException { - String v = getString(cr, name); + return getIntForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static int getIntForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userHandle); try { return Integer.parseInt(v); } catch (NumberFormatException e) { @@ -942,7 +1064,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putInt(ContentResolver cr, String name, int value) { - return putString(cr, name, Integer.toString(value)); + return putIntForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putIntForUser(ContentResolver cr, String name, int value, + int userHandle) { + return putStringForUser(cr, name, Integer.toString(value), userHandle); } /** @@ -960,7 +1088,13 @@ public final class Settings { * or not a valid {@code long}. */ public static long getLong(ContentResolver cr, String name, long def) { - String valString = getString(cr, name); + return getLongForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static long getLongForUser(ContentResolver cr, String name, long def, + int userHandle) { + String valString = getStringForUser(cr, name, userHandle); long value; try { value = valString != null ? Long.parseLong(valString) : def; @@ -989,7 +1123,13 @@ public final class Settings { */ public static long getLong(ContentResolver cr, String name) throws SettingNotFoundException { - String valString = getString(cr, name); + return getLongForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static long getLongForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String valString = getStringForUser(cr, name, userHandle); try { return Long.parseLong(valString); } catch (NumberFormatException e) { @@ -1011,7 +1151,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putLong(ContentResolver cr, String name, long value) { - return putString(cr, name, Long.toString(value)); + return putLongForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putLongForUser(ContentResolver cr, String name, long value, + int userHandle) { + return putStringForUser(cr, name, Long.toString(value), userHandle); } /** @@ -1029,7 +1175,13 @@ public final class Settings { * or not a valid float. */ public static float getFloat(ContentResolver cr, String name, float def) { - String v = getString(cr, name); + return getFloatForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static float getFloatForUser(ContentResolver cr, String name, float def, + int userHandle) { + String v = getStringForUser(cr, name, userHandle); try { return v != null ? Float.parseFloat(v) : def; } catch (NumberFormatException e) { @@ -1057,7 +1209,13 @@ public final class Settings { */ public static float getFloat(ContentResolver cr, String name) throws SettingNotFoundException { - String v = getString(cr, name); + return getFloatForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static float getFloatForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userHandle); if (v == null) { throw new SettingNotFoundException(name); } @@ -1082,7 +1240,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putFloat(ContentResolver cr, String name, float value) { - return putString(cr, name, Float.toString(value)); + return putFloatForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putFloatForUser(ContentResolver cr, String name, float value, + int userHandle) { + return putStringForUser(cr, name, Float.toString(value), userHandle); } /** @@ -1094,8 +1258,14 @@ public final class Settings { * @param outConfig Where to place the configuration settings. */ public static void getConfiguration(ContentResolver cr, Configuration outConfig) { - outConfig.fontScale = Settings.System.getFloat( - cr, FONT_SCALE, outConfig.fontScale); + getConfigurationForUser(cr, outConfig, UserHandle.myUserId()); + } + + /** @hide */ + public static void getConfigurationForUser(ContentResolver cr, Configuration outConfig, + int userHandle) { + outConfig.fontScale = Settings.System.getFloatForUser( + cr, FONT_SCALE, outConfig.fontScale, userHandle); if (outConfig.fontScale < 0) { outConfig.fontScale = 1; } @@ -1118,7 +1288,13 @@ public final class Settings { * @return true if the values were set, false on database errors */ public static boolean putConfiguration(ContentResolver cr, Configuration config) { - return Settings.System.putFloat(cr, FONT_SCALE, config.fontScale); + return putConfigurationForUser(cr, config, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putConfigurationForUser(ContentResolver cr, Configuration config, + int userHandle) { + return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle); } /** @hide */ @@ -1126,12 +1302,35 @@ public final class Settings { return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0; } + /** @deprecated - Do not use */ + @Deprecated public static boolean getShowGTalkServiceStatus(ContentResolver cr) { - return getInt(cr, SHOW_GTALK_SERVICE_STATUS, 0) != 0; + return getShowGTalkServiceStatusForUser(cr, UserHandle.myUserId()); } + /** + * @hide + * @deprecated - Do not use + */ + public static boolean getShowGTalkServiceStatusForUser(ContentResolver cr, + int userHandle) { + return getIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, 0, userHandle) != 0; + } + + /** @deprecated - Do not use */ + @Deprecated public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) { - putInt(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0); + /* intentionally empty */ + } + + /** + * @hide + * @deprecated - Do not use + */ + @Deprecated + public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean flag, + int userHandle) { + putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle); } /** @@ -1141,17 +1340,10 @@ public final class Settings { Uri.parse("content://" + AUTHORITY + "/system"); /** - * Whether we keep the device on while the device is plugged in. - * Supported values are: - *

- * These values can be OR-ed together. + * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead */ - public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; + @Deprecated + public static final String STAY_ON_WHILE_PLUGGED_IN = Global.STAY_ON_WHILE_PLUGGED_IN; /** * What happens when the user presses the end call button if they're not @@ -1196,80 +1388,81 @@ public final class Settings { public static final int ADVANCED_SETTINGS_DEFAULT = 0; /** - * Whether Airplane Mode is on. + * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_ON} instead */ - public static final String AIRPLANE_MODE_ON = "airplane_mode_on"; + @Deprecated + public static final String AIRPLANE_MODE_ON = Global.AIRPLANE_MODE_ON; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio. + * @deprecated Use {@link android.provider.Settings.Global#RADIO_BLUETOOTH} instead */ - public static final String RADIO_BLUETOOTH = "bluetooth"; + @Deprecated + public static final String RADIO_BLUETOOTH = Global.RADIO_BLUETOOTH; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio. + * @deprecated Use {@link android.provider.Settings.Global#RADIO_WIFI} instead */ - public static final String RADIO_WIFI = "wifi"; + @Deprecated + public static final String RADIO_WIFI = Global.RADIO_WIFI; /** + * @deprecated Use {@link android.provider.Settings.Global#RADIO_WIMAX} instead * {@hide} */ - public static final String RADIO_WIMAX = "wimax"; - /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify Cellular radio. - */ - public static final String RADIO_CELL = "cell"; + @Deprecated + public static final String RADIO_WIMAX = Global.RADIO_WIMAX; /** - * Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio. + * @deprecated Use {@link android.provider.Settings.Global#RADIO_CELL} instead */ - public static final String RADIO_NFC = "nfc"; + @Deprecated + public static final String RADIO_CELL = Global.RADIO_CELL; /** - * A comma separated list of radios that need to be disabled when airplane mode - * is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are - * included in the comma separated list. + * @deprecated Use {@link android.provider.Settings.Global#RADIO_NFC} instead */ - public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; + @Deprecated + public static final String RADIO_NFC = Global.RADIO_NFC; /** - * A comma separated list of radios that should to be disabled when airplane mode - * is on, but can be manually reenabled by the user. For example, if RADIO_WIFI is - * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi - * will be turned off when entering airplane mode, but the user will be able to reenable - * Wifi in the Settings app. + * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_RADIOS} instead + */ + @Deprecated + public static final String AIRPLANE_MODE_RADIOS = Global.AIRPLANE_MODE_RADIOS; + + /** + * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_TOGGLEABLE_RADIOS} instead * * {@hide} */ - public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios"; + @Deprecated + public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = + Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS; /** - * The policy for deciding when Wi-Fi should go to sleep (which will in - * turn switch to using the mobile data as an Internet connection). - *

- * Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT}, - * {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or - * {@link #WIFI_SLEEP_POLICY_NEVER}. + * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY} instead */ - public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy"; + @Deprecated + public static final String WIFI_SLEEP_POLICY = Global.WIFI_SLEEP_POLICY; /** - * Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep - * policy, which is to sleep shortly after the turning off - * according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting. + * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_DEFAULT} instead */ - public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; + @Deprecated + public static final int WIFI_SLEEP_POLICY_DEFAULT = Global.WIFI_SLEEP_POLICY_DEFAULT; /** - * Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when - * the device is on battery, and never go to sleep when the device is - * plugged in. + * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED} instead */ - public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; + @Deprecated + public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = + Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED; /** - * Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep. + * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_NEVER} instead */ - public static final int WIFI_SLEEP_POLICY_NEVER = 2; + @Deprecated + public static final int WIFI_SLEEP_POLICY_NEVER = Global.WIFI_SLEEP_POLICY_NEVER; //TODO: deprecate static IP constants /** @@ -1673,16 +1866,18 @@ public final class Settings { public static final String WALLPAPER_ACTIVITY = "wallpaper_activity"; /** - * Value to specify if the user prefers the date, time and time zone - * to be automatically fetched from the network (NITZ). 1=yes, 0=no + * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME} + * instead */ - public static final String AUTO_TIME = "auto_time"; + @Deprecated + public static final String AUTO_TIME = Global.AUTO_TIME; /** - * Value to specify if the user prefers the time zone - * to be automatically fetched from the network (NITZ). 1=yes, 0=no + * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME_ZONE} + * instead */ - public static final String AUTO_TIME_ZONE = "auto_time_zone"; + @Deprecated + public static final String AUTO_TIME_ZONE = Global.AUTO_TIME_ZONE; /** * Display times as 12 or 24 hours @@ -1883,16 +2078,20 @@ public final class Settings { "window_orientation_listener_log"; /** - * Whether to play a sound for low-battery alerts. + * @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED} + * instead * @hide */ - public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled"; + @Deprecated + public static final String POWER_SOUNDS_ENABLED = Global.POWER_SOUNDS_ENABLED; /** - * Whether to play a sound for dock events. + * @deprecated Use {@link android.provider.Settings.Global#DOCK_SOUNDS_ENABLED} + * instead * @hide */ - public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled"; + @Deprecated + public static final String DOCK_SOUNDS_ENABLED = Global.DOCK_SOUNDS_ENABLED; /** * Whether to play sounds when the keyguard is shown and dismissed. @@ -1907,46 +2106,60 @@ public final class Settings { public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled"; /** - * URI for the low battery sound file. + * @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND} + * instead * @hide */ - public static final String LOW_BATTERY_SOUND = "low_battery_sound"; + @Deprecated + public static final String LOW_BATTERY_SOUND = Global.LOW_BATTERY_SOUND; /** - * URI for the desk dock "in" event sound. + * @deprecated Use {@link android.provider.Settings.Global#DESK_DOCK_SOUND} + * instead * @hide */ - public static final String DESK_DOCK_SOUND = "desk_dock_sound"; + @Deprecated + public static final String DESK_DOCK_SOUND = Global.DESK_DOCK_SOUND; /** - * URI for the desk dock "out" event sound. + * @deprecated Use {@link android.provider.Settings.Global#DESK_UNDOCK_SOUND} + * instead * @hide */ - public static final String DESK_UNDOCK_SOUND = "desk_undock_sound"; + @Deprecated + public static final String DESK_UNDOCK_SOUND = Global.DESK_UNDOCK_SOUND; /** - * URI for the car dock "in" event sound. + * @deprecated Use {@link android.provider.Settings.Global#CAR_DOCK_SOUND} + * instead * @hide */ - public static final String CAR_DOCK_SOUND = "car_dock_sound"; + @Deprecated + public static final String CAR_DOCK_SOUND = Global.CAR_DOCK_SOUND; /** - * URI for the car dock "out" event sound. + * @deprecated Use {@link android.provider.Settings.Global#CAR_UNDOCK_SOUND} + * instead * @hide */ - public static final String CAR_UNDOCK_SOUND = "car_undock_sound"; + @Deprecated + public static final String CAR_UNDOCK_SOUND = Global.CAR_UNDOCK_SOUND; /** - * URI for the "device locked" (keyguard shown) sound. + * @deprecated Use {@link android.provider.Settings.Global#LOCK_SOUND} + * instead * @hide */ - public static final String LOCK_SOUND = "lock_sound"; + @Deprecated + public static final String LOCK_SOUND = Global.LOCK_SOUND; /** - * URI for the "device unlocked" (keyguard dismissed) sound. + * @deprecated Use {@link android.provider.Settings.Global#UNLOCK_SOUND} + * instead * @hide */ - public static final String UNLOCK_SOUND = "unlock_sound"; + @Deprecated + public static final String UNLOCK_SOUND = Global.UNLOCK_SOUND; /** * Receive incoming SIP calls? @@ -2066,11 +2279,11 @@ public final class Settings { // Settings moved to Settings.Secure /** - * @deprecated Use {@link android.provider.Settings.Secure#ADB_ENABLED} + * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} * instead */ @Deprecated - public static final String ADB_ENABLED = Secure.ADB_ENABLED; + public static final String ADB_ENABLED = Global.ADB_ENABLED; /** * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead @@ -2079,22 +2292,22 @@ public final class Settings { public static final String ANDROID_ID = Secure.ANDROID_ID; /** - * @deprecated Use {@link android.provider.Settings.Secure#BLUETOOTH_ON} instead + * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead */ @Deprecated - public static final String BLUETOOTH_ON = Secure.BLUETOOTH_ON; + public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; /** - * @deprecated Use {@link android.provider.Settings.Secure#DATA_ROAMING} instead + * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead */ @Deprecated - public static final String DATA_ROAMING = Secure.DATA_ROAMING; + public static final String DATA_ROAMING = Global.DATA_ROAMING; /** - * @deprecated Use {@link android.provider.Settings.Secure#DEVICE_PROVISIONED} instead + * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead */ @Deprecated - public static final String DEVICE_PROVISIONED = Secure.DEVICE_PROVISIONED; + public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; /** * @deprecated Use {@link android.provider.Settings.Secure#HTTP_PROXY} instead @@ -2103,10 +2316,10 @@ public final class Settings { public static final String HTTP_PROXY = Secure.HTTP_PROXY; /** - * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead + * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead */ @Deprecated - public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS; + public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS; /** * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} @@ -2122,10 +2335,10 @@ public final class Settings { public static final String LOGGING_ID = Secure.LOGGING_ID; /** - * @deprecated Use {@link android.provider.Settings.Secure#NETWORK_PREFERENCE} instead + * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead */ @Deprecated - public static final String NETWORK_PREFERENCE = Secure.NETWORK_PREFERENCE; + public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; /** * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED} @@ -2156,60 +2369,60 @@ public final class Settings { public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME; /** - * @deprecated Use {@link android.provider.Settings.Secure#USB_MASS_STORAGE_ENABLED} instead + * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead */ @Deprecated - public static final String USB_MASS_STORAGE_ENABLED = Secure.USB_MASS_STORAGE_ENABLED; + public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; /** - * @deprecated Use {@link android.provider.Settings.Secure#USE_GOOGLE_MAIL} instead + * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead */ @Deprecated - public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL; + public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; /** * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} instead + * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead */ @Deprecated - public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT; + public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; /** * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead */ @Deprecated public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = - Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; /** * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead + * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead */ @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = - Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; + Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; /** * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead + * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead */ @Deprecated public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = - Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; + Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT} + * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT} * instead */ @Deprecated - public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Secure.WIFI_NUM_OPEN_NETWORKS_KEPT; + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_ON} instead + * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead */ @Deprecated - public static final String WIFI_ON = Secure.WIFI_ON; + public static final String WIFI_ON = Global.WIFI_ON; /** * @deprecated Use @@ -2267,10 +2480,10 @@ public final class Settings { public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ON} instead + * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead */ @Deprecated - public static final String WIFI_WATCHDOG_ON = Secure.WIFI_WATCHDOG_ON; + public static final String WIFI_WATCHDOG_ON = Global.WIFI_WATCHDOG_ON; /** * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead @@ -2310,11 +2523,106 @@ public final class Settings { private static boolean sIsSystemProcess; private static final HashSet MOVED_TO_LOCK_SETTINGS; + private static final HashSet MOVED_TO_GLOBAL; static { MOVED_TO_LOCK_SETTINGS = new HashSet(3); MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED); MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE); MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED); + + MOVED_TO_GLOBAL = new HashSet(); + MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.ASSISTED_GPS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.BLUETOOTH_ON); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_CELL_BROADCAST_SMS); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_ROAMING_MODE); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_SUBSCRIPTION_MODE); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING); + MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED); + MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_DENSITY_FORCED); + MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED); + MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.INSTALL_NON_MARKET_APPS); + MOVED_TO_GLOBAL.add(Settings.Global.MOBILE_DATA); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_DELETE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_PERSIST_BYTES); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_ROTATE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_POLL_INTERVAL); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_REPORT_XT_OVER_DEV); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_SAMPLE_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_BUCKET_DURATION); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_DELETE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_PERSIST_BYTES); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_ROTATE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_DELETE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETWORK_PREFERENCE); + MOVED_TO_GLOBAL.add(Settings.Global.NITZ_UPDATE_DIFF); + MOVED_TO_GLOBAL.add(Settings.Global.NITZ_UPDATE_SPACING); + MOVED_TO_GLOBAL.add(Settings.Global.NTP_SERVER); + MOVED_TO_GLOBAL.add(Settings.Global.NTP_TIMEOUT); + MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT); + MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS); + MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT); + MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS); + MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT); + MOVED_TO_GLOBAL.add(Settings.Global.SAMPLING_PROFILER_MS); + MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL); + MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST); + MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL); + MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_APN); + MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_REQUIRED); + MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_HELP_URI); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_NOTIFICATION_TYPE); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_POLLING_SEC); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_RESET_DAY); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_THRESHOLD_BYTES); + MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_VALUE_KBITSPS); + MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL); + MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_IDLE_MS); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ON); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_P2P_DEVICE_NAME); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_NUM_ARP_PINGS); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS); + MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON); + MOVED_TO_GLOBAL.add(Settings.Global.WTF_IS_FATAL); + } + + private static void lazyInitCache() { + if (sNameValueCache == null) { + sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(), + CONTENT_URI, + CALL_METHOD_GET_SECURE, + CALL_METHOD_PUT_SECURE); + } } /** @@ -2324,9 +2632,16 @@ public final class Settings { * @return the corresponding value, or null if not present */ public synchronized static String getString(ContentResolver resolver, String name) { - if (sNameValueCache == null) { - sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI, - CALL_METHOD_GET_SECURE); + return getStringForUser(resolver, name, UserHandle.myUserId()); + } + + /** @hide */ + public synchronized static String getStringForUser(ContentResolver resolver, String name, + int userHandle) { + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + + " to android.provider.Settings.Global."); + return Global.getStringForUser(resolver, name, userHandle); } if (sLockSettings == null) { @@ -2337,13 +2652,14 @@ public final class Settings { if (sLockSettings != null && !sIsSystemProcess && MOVED_TO_LOCK_SETTINGS.contains(name)) { try { - return sLockSettings.getString(name, "0", UserHandle.getCallingUserId()); + return sLockSettings.getString(name, "0", userHandle); } catch (RemoteException re) { // Fall through } } - return sNameValueCache.getString(resolver, name); + lazyInitCache(); + return sNameValueCache.getStringForUser(resolver, name, userHandle); } /** @@ -2353,9 +2669,20 @@ public final class Settings { * @param value to associate with the name * @return true if the value was set, false on database errors */ - public static boolean putString(ContentResolver resolver, - String name, String value) { - return putString(resolver, CONTENT_URI, name, value); + public static boolean putString(ContentResolver resolver, String name, String value) { + return putStringForUser(resolver, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putStringForUser(ContentResolver resolver, String name, String value, + int userHandle) { + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System" + + " to android.provider.Settings.Global"); + return Global.putStringForUser(resolver, name, value, userHandle); + } + lazyInitCache(); + return sNameValueCache.putStringForUser(resolver, name, value, userHandle); } /** @@ -2365,6 +2692,11 @@ public final class Settings { * @return the corresponding content URI, or null if not present */ public static Uri getUriFor(String name) { + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + + " to android.provider.Settings.Global, returning global URI."); + return Global.getUriFor(Global.CONTENT_URI, name); + } return getUriFor(CONTENT_URI, name); } @@ -2383,7 +2715,12 @@ public final class Settings { * or not a valid integer. */ public static int getInt(ContentResolver cr, String name, int def) { - String v = getString(cr, name); + return getIntForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) { + String v = getStringForUser(cr, name, userHandle); try { return v != null ? Integer.parseInt(v) : def; } catch (NumberFormatException e) { @@ -2411,7 +2748,13 @@ public final class Settings { */ public static int getInt(ContentResolver cr, String name) throws SettingNotFoundException { - String v = getString(cr, name); + return getIntForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static int getIntForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userHandle); try { return Integer.parseInt(v); } catch (NumberFormatException e) { @@ -2433,7 +2776,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putInt(ContentResolver cr, String name, int value) { - return putString(cr, name, Integer.toString(value)); + return putIntForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putIntForUser(ContentResolver cr, String name, int value, + int userHandle) { + return putStringForUser(cr, name, Integer.toString(value), userHandle); } /** @@ -2451,7 +2800,13 @@ public final class Settings { * or not a valid {@code long}. */ public static long getLong(ContentResolver cr, String name, long def) { - String valString = getString(cr, name); + return getLongForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static long getLongForUser(ContentResolver cr, String name, long def, + int userHandle) { + String valString = getStringForUser(cr, name, userHandle); long value; try { value = valString != null ? Long.parseLong(valString) : def; @@ -2480,7 +2835,13 @@ public final class Settings { */ public static long getLong(ContentResolver cr, String name) throws SettingNotFoundException { - String valString = getString(cr, name); + return getLongForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static long getLongForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String valString = getStringForUser(cr, name, userHandle); try { return Long.parseLong(valString); } catch (NumberFormatException e) { @@ -2502,7 +2863,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putLong(ContentResolver cr, String name, long value) { - return putString(cr, name, Long.toString(value)); + return putLongForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putLongForUser(ContentResolver cr, String name, long value, + int userHandle) { + return putStringForUser(cr, name, Long.toString(value), userHandle); } /** @@ -2520,7 +2887,13 @@ public final class Settings { * or not a valid float. */ public static float getFloat(ContentResolver cr, String name, float def) { - String v = getString(cr, name); + return getFloatForUser(cr, name, def, UserHandle.myUserId()); + } + + /** @hide */ + public static float getFloatForUser(ContentResolver cr, String name, float def, + int userHandle) { + String v = getStringForUser(cr, name, userHandle); try { return v != null ? Float.parseFloat(v) : def; } catch (NumberFormatException e) { @@ -2548,7 +2921,13 @@ public final class Settings { */ public static float getFloat(ContentResolver cr, String name) throws SettingNotFoundException { - String v = getString(cr, name); + return getFloatForUser(cr, name, UserHandle.myUserId()); + } + + /** @hide */ + public static float getFloatForUser(ContentResolver cr, String name, int userHandle) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userHandle); if (v == null) { throw new SettingNotFoundException(name); } @@ -2573,7 +2952,13 @@ public final class Settings { * @return true if the value was set, false on database errors */ public static boolean putFloat(ContentResolver cr, String name, float value) { - return putString(cr, name, Float.toString(value)); + return putFloatForUser(cr, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putFloatForUser(ContentResolver cr, String name, float value, + int userHandle) { + return putStringForUser(cr, name, Float.toString(value), userHandle); } /** @@ -2583,9 +2968,12 @@ public final class Settings { Uri.parse("content://" + AUTHORITY + "/secure"); /** - * Whether user has enabled development settings. + * @deprecated Use {@link android.provider.Settings.Global#DEVELOPMENT_SETTINGS_ENABLED} + * instead */ - public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; + @Deprecated + public static final String DEVELOPMENT_SETTINGS_ENABLED = + Global.DEVELOPMENT_SETTINGS_ENABLED; /** * When the user has enable the option to have a "bug report" command @@ -2595,9 +2983,10 @@ public final class Settings { public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu"; /** - * Whether ADB is enabled. + * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead */ - public static final String ADB_ENABLED = "adb_enabled"; + @Deprecated + public static final String ADB_ENABLED = Global.ADB_ENABLED; /** * Setting to allow mock locations and location provider status to be injected into the @@ -2616,10 +3005,10 @@ public final class Settings { public static final String ANDROID_ID = "android_id"; /** - * Whether bluetooth is enabled/disabled - * 0=disabled. 1=enabled. + * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead */ - public static final String BLUETOOTH_ON = "bluetooth_on"; + @Deprecated + public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; /** * Get the key that retrieves a bluetooth headset's priority. @@ -2646,9 +3035,9 @@ public final class Settings { } /** - * Whether or not data roaming is enabled. (0 = false, 1 = true) + * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead */ - public static final String DATA_ROAMING = "data_roaming"; + public static final String DATA_ROAMING = Global.DATA_ROAMING; /** * Setting to record the input method used by default, holding the ID @@ -2678,9 +3067,10 @@ public final class Settings { "input_method_selector_visibility"; /** - * Whether the device has been provisioned (0 = false, 1 = true) + * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead */ - public static final String DEVICE_PROVISIONED = "device_provisioned"; + @Deprecated + public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; /** * List of input methods that are currently enabled. This is a string @@ -2739,13 +3129,10 @@ public final class Settings { public static final String DEFAULT_DNS_SERVER = "default_dns_server"; /** - * Whether the package installer should allow installation of apps downloaded from - * sources other than Google Play. - * - * 1 = allow installing from other sources - * 0 = only allow installing from Google Play + * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead */ - public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + @Deprecated + public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS; /** * Comma-separated list of location providers that activities may access. @@ -2797,24 +3184,25 @@ public final class Settings { "lock_screen_owner_info_enabled"; /** - * The saved value for WindowManagerService.setForcedDisplaySize(). - * Two integers separated by a comma. If unset, then use the real display size. + * @deprecated Use {@link android.provider.Settings.Global#DISPLAY_SIZE_FORCED} instead * @hide */ - public static final String DISPLAY_SIZE_FORCED = "display_size_forced"; + @Deprecated + public static final String DISPLAY_SIZE_FORCED = Global.DISPLAY_SIZE_FORCED; /** - * The saved value for WindowManagerService.setForcedDisplayDensity(). - * One integer in dpi. If unset, then use the real display density. + * @deprecated Use {@link android.provider.Settings.Global#DISPLAY_DENSITY_FORCED} instead * @hide */ - public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; + @Deprecated + public static final String DISPLAY_DENSITY_FORCED = Global.DISPLAY_DENSITY_FORCED; /** - * Whether assisted GPS should be enabled or not. + * @deprecated Use {@link android.provider.Settings.Global#ASSISTED_GPS_ENABLE} instead * @hide */ - public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled"; + @Deprecated + public static final String ASSISTED_GPS_ENABLED = Global.ASSISTED_GPS_ENABLED; /** * The Logging ID (a unique 64-bit value) as a hex string. @@ -2826,57 +3214,48 @@ public final class Settings { public static final String LOGGING_ID = "logging_id"; /** - * User preference for which network(s) should be used. Only the - * connectivity service should touch this. + * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead */ - public static final String NETWORK_PREFERENCE = "network_preference"; + @Deprecated + public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; /** - * Used to disable Tethering on a device - defaults to true + * @deprecated Use {@link android.provider.Settings.Global#TETHER_SUPPORTED} instead * @hide */ - public static final String TETHER_SUPPORTED = "tether_supported"; + @Deprecated + public static final String TETHER_SUPPORTED = Global.TETHER_SUPPORTED; /** - * Used to require DUN APN on the device or not - defaults to a build config value - * which defaults to false + * @deprecated Use {@link android.provider.Settings.Global#TETHER_DUN_REQUIRED} instead * @hide */ - public static final String TETHER_DUN_REQUIRED = "tether_dun_required"; + @Deprecated + public static final String TETHER_DUN_REQUIRED = Global.TETHER_DUN_REQUIRED; /** - * Used to hold a gservices-provisioned apn value for DUN. If set, or the - * corresponding build config values are set it will override the APN DB - * values. - * Consists of a comma seperated list of strings: - * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" - * note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" + * @deprecated Use {@link android.provider.Settings.Global#TETHER_DUN_REQUIRED} instead * @hide */ - public static final String TETHER_DUN_APN = "tether_dun_apn"; + @Deprecated + public static final String TETHER_DUN_APN = Global.TETHER_DUN_APN; - /** Inactivity timeout to track mobile data activity. - * - * If set to a positive integer, it indicates the inactivity timeout value in seconds to - * infer the data activity of mobile network. After a period of no activity on mobile - * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE} - * intent is fired to indicate a transition of network status from "active" to "idle". Any - * subsequent activity on mobile networks triggers the firing of {@code - * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active". - * - * Network activity refers to transmitting or receiving data on the network interfaces. - * - * Tracking is disabled if set to zero or negative value. - * + /** + * @deprecated Use {@link android.provider.Settings.Global#DATA_ACTIVITY_TIMEOUT_MOBILE} + * instead * @hide */ - public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile"; + @Deprecated + public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = + Global.DATA_ACTIVITY_TIMEOUT_MOBILE; - /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE} - * but for Wifi network. + /** + * @deprecated Use {@link android.provider.Settings.Global#DATA_ACTIVITY_TIMEOUT_MOBILE} + * instead * @hide */ - public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi"; + @Deprecated + public static final String DATA_ACTIVITY_TIMEOUT_WIFI = Global.DATA_ACTIVITY_TIMEOUT_WIFI; /** * No longer supported. @@ -2894,13 +3273,11 @@ public final class Settings { public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; /** - * A positive value indicates how often the SamplingProfiler - * should take snapshots. Zero value means SamplingProfiler - * is disabled. - * + * @deprecated Use {@link android.provider.Settings.Global#SAMPLING_PROFILER_MS} instead * @hide */ - public static final String SAMPLING_PROFILER_MS = "sampling_profiler_ms"; + @Deprecated + public static final String SAMPLING_PROFILER_MS = Global.SAMPLING_PROFILER_MS; /** * Settings classname to launch when Settings is clicked from All @@ -2911,15 +3288,16 @@ public final class Settings { public static final String SETTINGS_CLASSNAME = "settings_classname"; /** - * USB Mass Storage Enabled + * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead */ - public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; + @Deprecated + public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; /** - * If this setting is set (to anything), then all references - * to Gmail on the device must change to Google Mail. + * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead */ - public static final String USE_GOOGLE_MAIL = "use_google_mail"; + @Deprecated + public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; /** * If accessibility is enabled. @@ -3315,11 +3693,11 @@ public final class Settings { "wifi_suspend_optimizations_enabled"; /** - * The maximum number of times we will retry a connection to an access - * point for which we have failed in acquiring an IP address from DHCP. - * A value of N means that we will make N+1 connection attempts in all. + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead */ - public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + @Deprecated + public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; /** * The operational wifi frequency band @@ -3380,26 +3758,25 @@ public final class Settings { = "allowed_geolocation_origins"; /** - * Whether mobile data connections are allowed by the user. See - * ConnectivityManager for more info. + * @deprecated Use {@link android.provider.Settings.Global#MOBILE_DATA} instead * @hide */ - public static final String MOBILE_DATA = "mobile_data"; + @Deprecated + public static final String MOBILE_DATA = Global.MOBILE_DATA; /** - * The CDMA roaming mode 0 = Home Networks, CDMA default - * 1 = Roaming on Affiliated networks - * 2 = Roaming on any networks + * @deprecated Use {@link android.provider.Settings.Global#CDMA_ROAMING_MODE} instead * @hide */ - public static final String CDMA_ROAMING_MODE = "roaming_settings"; + @Deprecated + public static final String CDMA_ROAMING_MODE = Global.CDMA_ROAMING_MODE; /** - * The CDMA subscription mode 0 = RUIM/SIM (default) - * 1 = NV + * @deprecated Use {@link android.provider.Settings.Global#CDMA_ROAMING_MODE} instead * @hide */ - public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode"; + @Deprecated + public static final String CDMA_SUBSCRIPTION_MODE = Global.CDMA_SUBSCRIPTION_MODE; /** * The preferred network mode 7 = Global @@ -3427,13 +3804,11 @@ public final class Settings { /** - * CDMA Cell Broadcast SMS - * 0 = CDMA Cell Broadcast SMS disabled - * 1 = CDMA Cell Broadcast SMS enabled + * @deprecated Use {@link android.provider.Settings.Global#CDMA_CELL_BROADCAST_SMS} instead * @hide */ - public static final String CDMA_CELL_BROADCAST_SMS = - "cdma_cell_broadcast_sms"; + @Deprecated + public static final String CDMA_CELL_BROADCAST_SMS = Global.CDMA_CELL_BROADCAST_SMS; /** * The cdma subscription 0 = Subscription from RUIM, when available @@ -3653,10 +4028,11 @@ public final class Settings { public static final String SEND_ACTION_APP_ERROR = "send_action_app_error"; /** - * Nonzero causes Log.wtf() to crash. + * @deprecated Use {@link android.provider.Settings.Global#WTF_IS_FATAL} instead * @hide */ - public static final String WTF_IS_FATAL = "wtf_is_fatal"; + @Deprecated + public static final String WTF_IS_FATAL = Global.WTF_IS_FATAL; /** * Maximum age of entries kept by {@link com.android.internal.os.IDropBoxManagerService}. @@ -3786,57 +4162,52 @@ public final class Settings { "wifi_supplicant_scan_interval_ms"; /** - * The interval in milliseconds at which to check packet counts on the - * mobile data interface when screen is on, to detect possible data - * connection problems. + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_POLL_INTERVAL_MS = - "pdp_watchdog_poll_interval_ms"; + Global.PDP_WATCHDOG_POLL_INTERVAL_MS; /** - * The interval in milliseconds at which to check packet counts on the - * mobile data interface when screen is off, to detect possible data - * connection problems. + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS = - "pdp_watchdog_long_poll_interval_ms"; + Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS; /** - * The interval in milliseconds at which to check packet counts on the - * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} - * outgoing packets has been reached without incoming packets. + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = - "pdp_watchdog_error_poll_interval_ms"; + Global.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS; /** - * The number of outgoing packets sent without seeing an incoming packet - * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT} - * device is logged to the event log + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT = - "pdp_watchdog_trigger_packet_count"; + Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT; /** - * The number of polls to perform (at {@link #PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS}) - * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before - * attempting data connection recovery. + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_ERROR_POLL_COUNT = - "pdp_watchdog_error_poll_count"; + Global.PDP_WATCHDOG_ERROR_POLL_COUNT; /** - * The number of failed PDP reset attempts before moving to something more - * drastic: re-registering to the network. + * @deprecated Moved to Settings.Global * @hide */ + @Deprecated public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = - "pdp_watchdog_max_pdp_reset_fail_count"; + Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT; /** * The number of milliseconds to delay when checking for data stalls during @@ -3865,19 +4236,16 @@ public final class Settings { "gprs_register_check_period_ms"; /** - * The length of time in milli-seconds that automatic small adjustments to - * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded. + * @deprecated Use {@link android.provider.Settings.Global#NITZ_UPDATE_SPACING} instead * @hide */ - public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing"; + public static final String NITZ_UPDATE_SPACING = Global.NITZ_UPDATE_SPACING; /** - * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment - * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been - * exceeded. + * @deprecated Use {@link android.provider.Settings.Global#NITZ_UPDATE_SPACING} instead * @hide */ - public static final String NITZ_UPDATE_DIFF = "nitz_update_diff"; + public static final String NITZ_UPDATE_DIFF = Global.NITZ_UPDATE_DIFF; /** * The maximum reconnect delay for short network outages or when the network is suspended @@ -4139,65 +4507,70 @@ public final class Settings { public static final String DEFAULT_INSTALL_LOCATION = "default_install_location"; /** - * The bandwidth throttle polling freqency in seconds + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_POLLING_SEC} instead * @hide */ - public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec"; + @Deprecated + public static final String THROTTLE_POLLING_SEC = Global.THROTTLE_POLLING_SEC; /** - * The bandwidth throttle threshold (long) + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_THRESHOLD_BYTES} instead * @hide */ - public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes"; + @Deprecated + public static final String THROTTLE_THRESHOLD_BYTES = Global.THROTTLE_THRESHOLD_BYTES; /** - * The bandwidth throttle value (kbps) + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_VALUE_KBITSPS} instead * @hide */ - public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps"; + @Deprecated + public static final String THROTTLE_VALUE_KBITSPS = Global.THROTTLE_VALUE_KBITSPS; /** - * The bandwidth throttle reset calendar day (1-28) + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_VALUE_KBITSPS} instead * @hide */ - public static final String THROTTLE_RESET_DAY = "throttle_reset_day"; + @Deprecated + public static final String THROTTLE_RESET_DAY = Global.THROTTLE_RESET_DAY; /** - * The throttling notifications we should send + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_NOTIFICATION_TYPE} instead * @hide */ - public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type"; + @Deprecated + public static final String THROTTLE_NOTIFICATION_TYPE = Global.THROTTLE_NOTIFICATION_TYPE; /** - * Help URI for data throttling policy + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_HELP_URI} instead * @hide */ - public static final String THROTTLE_HELP_URI = "throttle_help_uri"; + @Deprecated + public static final String THROTTLE_HELP_URI = Global.THROTTLE_HELP_URI; /** - * The length of time in Sec that we allow our notion of NTP time - * to be cached before we refresh it + * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_MAX_NTP_CACHE_AGE_SEC} instead * @hide */ + @Deprecated public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC = - "throttle_max_ntp_cache_age_sec"; + Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC; /** - * The maximum size, in bytes, of a download that the download manager will transfer over - * a non-wifi connection. + * @deprecated Use {@link android.provider.Settings.Global#DOWNLOAD_MAX_BYTES_OVER_MOBILE} instead * @hide */ + @Deprecated public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE = - "download_manager_max_bytes_over_mobile"; + Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE; /** - * The recommended maximum size, in bytes, of a download that the download manager should - * transfer over a non-wifi connection. Over this size, the use will be warned, but will - * have the option to start the download over the mobile connection anyway. + * @deprecated Use {@link android.provider.Settings.Global#DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE} instead * @hide */ + @Deprecated public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE = - "download_manager_recommended_max_bytes_over_mobile"; + Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE; /** * ms during which to consume extra events related to Inet connection condition @@ -4216,27 +4589,28 @@ public final class Settings { "inet_condition_debounce_down_delay"; /** - * URL to open browser on to allow user to manage a prepay account + * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DATA_SERVICE_URL} instead * @hide */ + @Deprecated public static final String SETUP_PREPAID_DATA_SERVICE_URL = - "setup_prepaid_data_service_url"; + Global.SETUP_PREPAID_DATA_SERVICE_URL; /** - * URL to attempt a GET on to see if this is a prepay device + * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DETECTION_TARGET_URL} instead * @hide */ + @Deprecated public static final String SETUP_PREPAID_DETECTION_TARGET_URL = - "setup_prepaid_detection_target_url"; + Global.SETUP_PREPAID_DETECTION_TARGET_URL; /** - * Host to check for a redirect to after an attempt to GET - * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there, - * this is a prepaid device with zero balance.) + * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DETECTION_REDIR_HOST} instead * @hide */ + @Deprecated public static final String SETUP_PREPAID_DETECTION_REDIR_HOST = - "setup_prepaid_detection_redir_host"; + Global.SETUP_PREPAID_DETECTION_REDIR_HOST; /** * Whether screensavers are enabled. @@ -4273,54 +4647,94 @@ public final class Settings { */ public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component"; - /** {@hide} */ - public static final String NETSTATS_ENABLED = "netstats_enabled"; - /** {@hide} */ - public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval"; - /** {@hide} */ - public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age"; - /** {@hide} */ - public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes"; - /** {@hide} */ - public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled"; - /** {@hide} */ - public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev"; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_ENABLED = Global.NETSTATS_ENABLED; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_POLL_INTERVAL = Global.NETSTATS_POLL_INTERVAL; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_TIME_CACHE_MAX_AGE = Global.NETSTATS_TIME_CACHE_MAX_AGE; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_GLOBAL_ALERT_BYTES = Global.NETSTATS_GLOBAL_ALERT_BYTES; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_SAMPLE_ENABLED = Global.NETSTATS_SAMPLE_ENABLED; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_REPORT_XT_OVER_DEV = Global.NETSTATS_REPORT_XT_OVER_DEV; - /** {@hide} */ - public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration"; - /** {@hide} */ - public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes"; - /** {@hide} */ - public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age"; - /** {@hide} */ - public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age"; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_DEV_BUCKET_DURATION = Global.NETSTATS_DEV_BUCKET_DURATION; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_DEV_PERSIST_BYTES = Global.NETSTATS_DEV_PERSIST_BYTES; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_DEV_ROTATE_AGE = Global.NETSTATS_DEV_ROTATE_AGE; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_DEV_DELETE_AGE = Global.NETSTATS_DEV_DELETE_AGE; - /** {@hide} */ - public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration"; - /** {@hide} */ - public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes"; - /** {@hide} */ - public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age"; - /** {@hide} */ - public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age"; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_BUCKET_DURATION = Global.NETSTATS_UID_BUCKET_DURATION; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_PERSIST_BYTES = Global.NETSTATS_UID_PERSIST_BYTES; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_ROTATE_AGE = Global.NETSTATS_UID_ROTATE_AGE; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_DELETE_AGE = Global.NETSTATS_UID_DELETE_AGE; - /** {@hide} */ - public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration"; - /** {@hide} */ - public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes"; - /** {@hide} */ - public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age"; - /** {@hide} */ - public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age"; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_TAG_BUCKET_DURATION = Global.NETSTATS_UID_TAG_BUCKET_DURATION; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_TAG_PERSIST_BYTES = Global.NETSTATS_UID_TAG_PERSIST_BYTES; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_TAG_ROTATE_AGE = Global.NETSTATS_UID_TAG_ROTATE_AGE; + /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now + * {@hide} */ + @Deprecated + public static final String NETSTATS_UID_TAG_DELETE_AGE = Global.NETSTATS_UID_TAG_DELETE_AGE; - /** Preferred NTP server. {@hide} */ - public static final String NTP_SERVER = "ntp_server"; - /** Timeout in milliseconds to wait for NTP server. {@hide} */ - public static final String NTP_TIMEOUT = "ntp_timeout"; + /** Preferred NTP server. {@hide} + * @deprecated moved to Settings.Global */ + public static final String NTP_SERVER = Global.NTP_SERVER; - /** Autofill server address (Used in WebView/browser). {@hide} */ - public static final String WEB_AUTOFILL_QUERY_URL = - "web_autofill_query_url"; + /** Timeout in milliseconds to wait for NTP server. {@hide} + * @deprecated moved to Settings.Global */ + public static final String NTP_TIMEOUT = Global.NTP_TIMEOUT; + + /** Autofill server address (Used in WebView/browser). + * @deprecated moved to Settings.Global + * {@hide} */ + public static final String WEB_AUTOFILL_QUERY_URL = Global.WEB_AUTOFILL_QUERY_URL; /** * Whether the package manager should send package verification broadcasts for verifiers to @@ -4450,6 +4864,955 @@ public final class Settings { } } + /** + * Global system settings, containing preferences that always apply identically + * to all defined users. Applications can read these but are not allowed to write; + * like the "Secure" settings, these are for preferences that the user must + * explicitly modify through the system UI or specialized APIs for those values. + */ + public static final class Global extends NameValueTable { + public static final String SYS_PROP_SETTING_VERSION = "sys.settings_global_version"; + + /** + * The content:// style URL for global secure settings items. Not public. + */ + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global"); + + /** + * Whether Airplane Mode is on. + */ + public static final String AIRPLANE_MODE_ON = "airplane_mode_on"; + + /** + * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio. + */ + public static final String RADIO_BLUETOOTH = "bluetooth"; + + /** + * Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio. + */ + public static final String RADIO_WIFI = "wifi"; + + /** + * {@hide} + */ + public static final String RADIO_WIMAX = "wimax"; + /** + * Constant for use in AIRPLANE_MODE_RADIOS to specify Cellular radio. + */ + public static final String RADIO_CELL = "cell"; + + /** + * Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio. + */ + public static final String RADIO_NFC = "nfc"; + + /** + * A comma separated list of radios that need to be disabled when airplane mode + * is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are + * included in the comma separated list. + */ + public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios"; + + /** + * A comma separated list of radios that should to be disabled when airplane mode + * is on, but can be manually reenabled by the user. For example, if RADIO_WIFI is + * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi + * will be turned off when entering airplane mode, but the user will be able to reenable + * Wifi in the Settings app. + * + * {@hide} + */ + public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios"; + + /** + * The policy for deciding when Wi-Fi should go to sleep (which will in + * turn switch to using the mobile data as an Internet connection). + *

+ * Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT}, + * {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or + * {@link #WIFI_SLEEP_POLICY_NEVER}. + */ + public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy"; + + /** + * Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep + * policy, which is to sleep shortly after the turning off + * according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting. + */ + public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; + + /** + * Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when + * the device is on battery, and never go to sleep when the device is + * plugged in. + */ + public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; + + /** + * Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep. + */ + public static final int WIFI_SLEEP_POLICY_NEVER = 2; + + /** + * Value to specify if the user prefers the date, time and time zone + * to be automatically fetched from the network (NITZ). 1=yes, 0=no + */ + public static final String AUTO_TIME = "auto_time"; + + /** + * Value to specify if the user prefers the time zone + * to be automatically fetched from the network (NITZ). 1=yes, 0=no + */ + public static final String AUTO_TIME_ZONE = "auto_time_zone"; + + /** + * URI for the car dock "in" event sound. + * @hide + */ + public static final String CAR_DOCK_SOUND = "car_dock_sound"; + + /** + * URI for the car dock "out" event sound. + * @hide + */ + public static final String CAR_UNDOCK_SOUND = "car_undock_sound"; + + /** + * URI for the desk dock "in" event sound. + * @hide + */ + public static final String DESK_DOCK_SOUND = "desk_dock_sound"; + + /** + * URI for the desk dock "out" event sound. + * @hide + */ + public static final String DESK_UNDOCK_SOUND = "desk_undock_sound"; + + /** + * Whether to play a sound for dock events. + * @hide + */ + public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled"; + + /** + * URI for the "device locked" (keyguard shown) sound. + * @hide + */ + public static final String LOCK_SOUND = "lock_sound"; + + /** + * URI for the "device unlocked" sound. + * @hide + */ + public static final String UNLOCK_SOUND = "unlock_sound"; + + /** + * URI for the low battery sound file. + * @hide + */ + public static final String LOW_BATTERY_SOUND = "low_battery_sound"; + + /** + * Whether to play a sound for low-battery alerts. + * @hide + */ + public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled"; + + /** + * Whether we keep the device on while the device is plugged in. + * Supported values are: + *

+ * These values can be OR-ed together. + */ + public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in"; + + /** + * Whether ADB is enabled. + */ + public static final String ADB_ENABLED = "adb_enabled"; + + /** + * Whether assisted GPS should be enabled or not. + * @hide + */ + public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled"; + + /** + * Whether bluetooth is enabled/disabled + * 0=disabled. 1=enabled. + */ + public static final String BLUETOOTH_ON = "bluetooth_on"; + + /** + * CDMA Cell Broadcast SMS + * 0 = CDMA Cell Broadcast SMS disabled + * 1 = CDMA Cell Broadcast SMS enabled + * @hide + */ + public static final String CDMA_CELL_BROADCAST_SMS = + "cdma_cell_broadcast_sms"; + + /** + * The CDMA roaming mode 0 = Home Networks, CDMA default + * 1 = Roaming on Affiliated networks + * 2 = Roaming on any networks + * @hide + */ + public static final String CDMA_ROAMING_MODE = "roaming_settings"; + + /** + * The CDMA subscription mode 0 = RUIM/SIM (default) + * 1 = NV + * @hide + */ + public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode"; + + /** Inactivity timeout to track mobile data activity. + * + * If set to a positive integer, it indicates the inactivity timeout value in seconds to + * infer the data activity of mobile network. After a period of no activity on mobile + * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE} + * intent is fired to indicate a transition of network status from "active" to "idle". Any + * subsequent activity on mobile networks triggers the firing of {@code + * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active". + * + * Network activity refers to transmitting or receiving data on the network interfaces. + * + * Tracking is disabled if set to zero or negative value. + * + * @hide + */ + public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile"; + + /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE} + * but for Wifi network. + * @hide + */ + public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi"; + + /** + * Whether or not data roaming is enabled. (0 = false, 1 = true) + */ + public static final String DATA_ROAMING = "data_roaming"; + + /** + * Whether user has enabled development settings. + */ + public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; + + /** + * Whether the device has been provisioned (0 = false, 1 = true) + */ + public static final String DEVICE_PROVISIONED = "device_provisioned"; + + /** + * The saved value for WindowManagerService.setForcedDisplayDensity(). + * One integer in dpi. If unset, then use the real display density. + * @hide + */ + public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; + + /** + * The saved value for WindowManagerService.setForcedDisplaySize(). + * Two integers separated by a comma. If unset, then use the real display size. + * @hide + */ + public static final String DISPLAY_SIZE_FORCED = "display_size_forced"; + + /** + * The maximum size, in bytes, of a download that the download manager will transfer over + * a non-wifi connection. + * @hide + */ + public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE = + "download_manager_max_bytes_over_mobile"; + + /** + * The recommended maximum size, in bytes, of a download that the download manager should + * transfer over a non-wifi connection. Over this size, the use will be warned, but will + * have the option to start the download over the mobile connection anyway. + * @hide + */ + public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE = + "download_manager_recommended_max_bytes_over_mobile"; + + /** + * Whether the package installer should allow installation of apps downloaded from + * sources other than Google Play. + * + * 1 = allow installing from other sources + * 0 = only allow installing from Google Play + */ + public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + + /** + * Whether mobile data connections are allowed by the user. See + * ConnectivityManager for more info. + * @hide + */ + public static final String MOBILE_DATA = "mobile_data"; + + /** {@hide} */ + public static final String NETSTATS_ENABLED = "netstats_enabled"; + /** {@hide} */ + public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval"; + /** {@hide} */ + public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age"; + /** {@hide} */ + public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes"; + /** {@hide} */ + public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled"; + /** {@hide} */ + public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev"; + + /** {@hide} */ + public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration"; + /** {@hide} */ + public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes"; + /** {@hide} */ + public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age"; + /** {@hide} */ + public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age"; + + /** {@hide} */ + public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration"; + /** {@hide} */ + public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes"; + /** {@hide} */ + public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age"; + /** {@hide} */ + public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age"; + + /** {@hide} */ + public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration"; + /** {@hide} */ + public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes"; + /** {@hide} */ + public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age"; + /** {@hide} */ + public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age"; + + /** + * User preference for which network(s) should be used. Only the + * connectivity service should touch this. + */ + public static final String NETWORK_PREFERENCE = "network_preference"; + + /** + * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment + * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been + * exceeded. + * @hide + */ + public static final String NITZ_UPDATE_DIFF = "nitz_update_diff"; + + /** + * The length of time in milli-seconds that automatic small adjustments to + * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded. + * @hide + */ + public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing"; + + /** Preferred NTP server. {@hide} */ + public static final String NTP_SERVER = "ntp_server"; + /** Timeout in milliseconds to wait for NTP server. {@hide} */ + public static final String NTP_TIMEOUT = "ntp_timeout"; + + /** + * The interval in milliseconds at which to check packet counts on the + * mobile data interface when screen is on, to detect possible data + * connection problems. + * @hide + */ + public static final String PDP_WATCHDOG_POLL_INTERVAL_MS = + "pdp_watchdog_poll_interval_ms"; + + /** + * The interval in milliseconds at which to check packet counts on the + * mobile data interface when screen is off, to detect possible data + * connection problems. + * @hide + */ + public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS = + "pdp_watchdog_long_poll_interval_ms"; + + /** + * The interval in milliseconds at which to check packet counts on the + * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} + * outgoing packets has been reached without incoming packets. + * @hide + */ + public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS = + "pdp_watchdog_error_poll_interval_ms"; + + /** + * The number of outgoing packets sent without seeing an incoming packet + * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT} + * device is logged to the event log + * @hide + */ + public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT = + "pdp_watchdog_trigger_packet_count"; + + /** + * The number of polls to perform (at {@link #PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS}) + * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before + * attempting data connection recovery. + * @hide + */ + public static final String PDP_WATCHDOG_ERROR_POLL_COUNT = + "pdp_watchdog_error_poll_count"; + + /** + * The number of failed PDP reset attempts before moving to something more + * drastic: re-registering to the network. + * @hide + */ + public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT = + "pdp_watchdog_max_pdp_reset_fail_count"; + + /** + * A positive value indicates how often the SamplingProfiler + * should take snapshots. Zero value means SamplingProfiler + * is disabled. + * + * @hide + */ + public static final String SAMPLING_PROFILER_MS = "sampling_profiler_ms"; + + /** + * URL to open browser on to allow user to manage a prepay account + * @hide + */ + public static final String SETUP_PREPAID_DATA_SERVICE_URL = + "setup_prepaid_data_service_url"; + + /** + * URL to attempt a GET on to see if this is a prepay device + * @hide + */ + public static final String SETUP_PREPAID_DETECTION_TARGET_URL = + "setup_prepaid_detection_target_url"; + + /** + * Host to check for a redirect to after an attempt to GET + * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there, + * this is a prepaid device with zero balance.) + * @hide + */ + public static final String SETUP_PREPAID_DETECTION_REDIR_HOST = + "setup_prepaid_detection_redir_host"; + + /** + * Used to disable Tethering on a device - defaults to true + * @hide + */ + public static final String TETHER_SUPPORTED = "tether_supported"; + + /** + * Used to require DUN APN on the device or not - defaults to a build config value + * which defaults to false + * @hide + */ + public static final String TETHER_DUN_REQUIRED = "tether_dun_required"; + + /** + * Used to hold a gservices-provisioned apn value for DUN. If set, or the + * corresponding build config values are set it will override the APN DB + * values. + * Consists of a comma seperated list of strings: + * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" + * note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" + * @hide + */ + public static final String TETHER_DUN_APN = "tether_dun_apn"; + + /** + * The bandwidth throttle polling freqency in seconds + * @hide + */ + public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec"; + + /** + * The bandwidth throttle threshold (long) + * @hide + */ + public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes"; + + /** + * The bandwidth throttle value (kbps) + * @hide + */ + public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps"; + + /** + * The bandwidth throttle reset calendar day (1-28) + * @hide + */ + public static final String THROTTLE_RESET_DAY = "throttle_reset_day"; + + /** + * The throttling notifications we should send + * @hide + */ + public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type"; + + /** + * Help URI for data throttling policy + * @hide + */ + public static final String THROTTLE_HELP_URI = "throttle_help_uri"; + + /** + * The length of time in Sec that we allow our notion of NTP time + * to be cached before we refresh it + * @hide + */ + public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC = + "throttle_max_ntp_cache_age_sec"; + + /** + * USB Mass Storage Enabled + */ + public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; + + /** + * If this setting is set (to anything), then all references + * to Gmail on the device must change to Google Mail. + */ + public static final String USE_GOOGLE_MAIL = "use_google_mail"; + + /** Autofill server address (Used in WebView/browser). + * {@hide} */ + public static final String WEB_AUTOFILL_QUERY_URL = + "web_autofill_query_url"; + + /** + * Whether to notify the user of open networks. + *

+ * If not connected and the scan results have an open network, we will + * put this notification up. If we attempt to connect to a network or + * the open network(s) disappear, we remove the notification. When we + * show the notification, we will not show it again for + * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time. + */ + public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = + "wifi_networks_available_notification_on"; + /** + * {@hide} + */ + public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON = + "wimax_networks_available_notification_on"; + + /** + * Delay (in seconds) before repeating the Wi-Fi networks available notification. + * Connecting to a network will reset the timer. + */ + public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = + "wifi_networks_available_repeat_delay"; + + /** + * 802.11 country code in ISO 3166 format + * @hide + */ + public static final String WIFI_COUNTRY_CODE = "wifi_country_code"; + + /** + * The interval in milliseconds to issue wake up scans when wifi needs + * to connect. This is necessary to connect to an access point when + * device is on the move and the screen is off. + * @hide + */ + public static final String WIFI_FRAMEWORK_SCAN_INTERVAL_MS = + "wifi_framework_scan_interval_ms"; + + /** + * The interval in milliseconds after which Wi-Fi is considered idle. + * When idle, it is possible for the device to be switched from Wi-Fi to + * the mobile data network. + * @hide + */ + public static final String WIFI_IDLE_MS = "wifi_idle_ms"; + + /** + * When the number of open networks exceeds this number, the + * least-recently-used excess networks will be removed. + */ + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept"; + + /** + * Whether the Wi-Fi should be on. Only the Wi-Fi service should touch this. + */ + public static final String WIFI_ON = "wifi_on"; + + /** + * Used to save the Wifi_ON state prior to tethering. + * This state will be checked to restore Wifi after + * the user turns off tethering. + * + * @hide + */ + public static final String WIFI_SAVED_STATE = "wifi_saved_state"; + + /** + * The interval in milliseconds to scan as used by the wifi supplicant + * @hide + */ + public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS = + "wifi_supplicant_scan_interval_ms"; + + /** + * Whether the Wi-Fi watchdog is enabled. + */ + public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; + + /** + * ms delay interval between rssi polling when the signal is known to be weak + * @hide + */ + public static final String WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS = + "wifi_watchdog_rssi_fetch_interval_ms"; + + /** + * Number of ARP pings per check. + * @hide + */ + public static final String WIFI_WATCHDOG_NUM_ARP_PINGS = "wifi_watchdog_num_arp_pings"; + + /** + * Setting to turn off poor network avoidance on Wi-Fi. Feature is enabled by default and + * the setting needs to be set to 0 to disable it. + * @hide + */ + public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED = + "wifi_watchdog_poor_network_test_enabled"; + + /** + * Setting to turn on suspend optimizations at screen off on Wi-Fi. Enabled by default and + * needs to be set to 0 to disable it. + * @hide + */ + public static final String WIFI_SUSPEND_OPTIMIZATIONS_ENABLED = + "wifi_suspend_optimizations_enabled"; + + /** + * The maximum number of times we will retry a connection to an access + * point for which we have failed in acquiring an IP address from DHCP. + * A value of N means that we will make N+1 connection attempts in all. + */ + public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; + + /** + * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile + * data connectivity to be established after a disconnect from Wi-Fi. + */ + public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = + "wifi_mobile_data_transition_wakelock_timeout_ms"; + + /** + * The operational wifi frequency band + * Set to one of {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, + * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ} or + * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ} + * + * @hide + */ + public static final String WIFI_FREQUENCY_BAND = "wifi_frequency_band"; + + /** + * The Wi-Fi peer-to-peer device name + * @hide + */ + public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name"; + + /** + * Nonzero causes Log.wtf() to crash. + * @hide + */ + public static final String WTF_IS_FATAL = "wtf_is_fatal"; + + + + + // Populated lazily, guarded by class object: + private static NameValueCache sNameValueCache = null; + + private static void lazyInitCache() { + if (sNameValueCache == null) { + sNameValueCache = new NameValueCache( + SYS_PROP_SETTING_VERSION, + CONTENT_URI, + CALL_METHOD_GET_GLOBAL, + CALL_METHOD_PUT_GLOBAL); + } + } + + /** + * Look up a name in the database. + * @param resolver to access the database with + * @param name to look up in the table + * @return the corresponding value, or null if not present + */ + public synchronized static String getString(ContentResolver resolver, String name) { + return getStringForUser(resolver, name, UserHandle.myUserId()); + } + + /** @hide */ + public synchronized static String getStringForUser(ContentResolver resolver, String name, + int userHandle) { + lazyInitCache(); + return sNameValueCache.getStringForUser(resolver, name, userHandle); + } + + /** + * Store a name/value pair into the database. + * @param resolver to access the database with + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + */ + public static boolean putString(ContentResolver resolver, + String name, String value) { + return putStringForUser(resolver, name, value, UserHandle.myUserId()); + } + + /** @hide */ + public static boolean putStringForUser(ContentResolver resolver, + String name, String value, int userHandle) { + lazyInitCache(); + if (LOCAL_LOGV) { + Log.v(TAG, "Global.putString(name=" + name + ", value=" + value + + " for " + userHandle); + } + return sNameValueCache.putStringForUser(resolver, name, value, userHandle); + } + + /** + * Construct the content URI for a particular name/value pair, + * useful for monitoring changes with a ContentObserver. + * @param name to look up in the table + * @return the corresponding content URI, or null if not present + */ + public static Uri getUriFor(String name) { + return getUriFor(CONTENT_URI, name); + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. The default value will be returned if the setting is + * not defined or not an integer. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid integer. + */ + public static int getInt(ContentResolver cr, String name, int def) { + String v = getString(cr, name); + try { + return v != null ? Integer.parseInt(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + * + * @return The setting's current value. + */ + public static int getInt(ContentResolver cr, String name) + throws SettingNotFoundException { + String v = getString(cr, name); + try { + return Integer.parseInt(v); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as an + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putInt(ContentResolver cr, String name, int value) { + return putString(cr, name, Integer.toString(value)); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. The default value will be returned if the setting is + * not defined or not a {@code long}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid {@code long}. + */ + public static long getLong(ContentResolver cr, String name, long def) { + String valString = getString(cr, name); + long value; + try { + value = valString != null ? Long.parseLong(valString) : def; + } catch (NumberFormatException e) { + value = def; + } + return value; + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @return The setting's current value. + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + */ + public static long getLong(ContentResolver cr, String name) + throws SettingNotFoundException { + String valString = getString(cr, name); + try { + return Long.parseLong(valString); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a secure settings value as a long + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putLong(ContentResolver cr, String name, long value) { + return putString(cr, name, Long.toString(value)); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a floating point number. Note that internally setting values are + * always stored as strings; this function converts the string to an + * float for you. The default value will be returned if the setting + * is not defined or not a valid float. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid float. + */ + public static float getFloat(ContentResolver cr, String name, float def) { + String v = getString(cr, name); + try { + return v != null ? Float.parseFloat(v) : def; + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Convenience function for retrieving a single secure settings value + * as a float. Note that internally setting values are always + * stored as strings; this function converts the string to a float + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not a float. + * + * @return The setting's current value. + */ + public static float getFloat(ContentResolver cr, String name) + throws SettingNotFoundException { + String v = getString(cr, name); + if (v == null) { + throw new SettingNotFoundException(name); + } + try { + return Float.parseFloat(v); + } catch (NumberFormatException e) { + throw new SettingNotFoundException(name); + } + } + + /** + * Convenience function for updating a single settings value as a + * floating point number. This will either create a new entry in the + * table if the given name does not exist, or modify the value of the + * existing row with that name. Note that internally setting values + * are always stored as strings, so this function converts the given + * value to a string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putFloat(ContentResolver cr, String name, float value) { + return putString(cr, name, Float.toString(value)); + } + } + /** * User-defined bookmarks and shortcuts. The target of each bookmark is an * Intent URL, allowing it to be either a web page or a particular diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 9c4111996c664..1be363ff57b23 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -30,7 +30,9 @@ import android.database.sqlite.SQLiteStatement; import android.media.AudioManager; import android.media.AudioService; import android.net.ConnectivityManager; +import android.os.Environment; import android.os.SystemProperties; +import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Secure; import android.telephony.TelephonyManager; @@ -48,6 +50,7 @@ import com.android.internal.widget.LockPatternView; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.List; @@ -64,15 +67,21 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 82; + private static final int DATABASE_VERSION = 83; private Context mContext; + private int mUserHandle; private static final HashSet mValidTables = new HashSet(); + private static final String TABLE_SYSTEM = "system"; + private static final String TABLE_SECURE = "secure"; + private static final String TABLE_GLOBAL = "global"; + static { - mValidTables.add("system"); - mValidTables.add("secure"); + mValidTables.add(TABLE_SYSTEM); + mValidTables.add(TABLE_SECURE); + mValidTables.add(TABLE_GLOBAL); mValidTables.add("bluetooth_devices"); mValidTables.add("bookmarks"); @@ -82,9 +91,23 @@ public class DatabaseHelper extends SQLiteOpenHelper { mValidTables.add("old_favorites"); } - public DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); + static String dbNameForUser(final int userHandle) { + // The owner gets the unadorned db name; + if (userHandle == UserHandle.USER_OWNER) { + return DATABASE_NAME; + } else { + // Place the database in the user-specific data tree so that it's + // cleaned up automatically when the user is deleted. + File databaseFile = new File( + Environment.getUserSystemDirectory(userHandle), DATABASE_NAME); + return databaseFile.getPath(); + } + } + + public DatabaseHelper(Context context, int userHandle) { + super(context, dbNameForUser(userHandle), null, DATABASE_VERSION); mContext = context; + mUserHandle = userHandle; setWriteAheadLoggingEnabled(true); } @@ -101,6 +124,15 @@ public class DatabaseHelper extends SQLiteOpenHelper { db.execSQL("CREATE INDEX secureIndex1 ON secure (name);"); } + private void createGlobalTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE global (" + + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + + "name TEXT UNIQUE ON CONFLICT REPLACE," + + "value TEXT" + + ");"); + db.execSQL("CREATE INDEX globalIndex1 ON global (name);"); + } + @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE system (" + @@ -112,6 +144,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { createSecureTable(db); + // Only create the global table for the singleton 'owner' user + if (mUserHandle == UserHandle.USER_OWNER) { + createGlobalTable(db); + } + db.execSQL("CREATE TABLE bluetooth_devices (" + "_id INTEGER PRIMARY KEY," + "name TEXT," + @@ -271,7 +308,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, }; - moveFromSystemToSecure(db, settingsToMove); + moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove); upgradeVersion = 28; } @@ -637,7 +674,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { "lockscreen.lockedoutpermanently", "lockscreen.password_salt" }; - moveFromSystemToSecure(db, settingsToMove); + moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove); upgradeVersion = 52; } @@ -687,7 +724,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { Secure.SET_INSTALL_LOCATION, Secure.DEFAULT_INSTALL_LOCATION }; - moveFromSystemToSecure(db, settingsToMove); + moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove); db.beginTransaction(); SQLiteStatement stmt = null; try { @@ -1013,7 +1050,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { SQLiteStatement stmt = null; Cursor c = null; try { - c = db.query("secure", new String[] {"_id", "value"}, + c = db.query(TABLE_SECURE, new String[] {"_id", "value"}, "name='lockscreen.disabled'", null, null, null, null); // only set default if it has not yet been set @@ -1089,14 +1126,14 @@ public class DatabaseHelper extends SQLiteOpenHelper { // toggle touch exploration. Note that the user has already manually // enabled the services and touch exploration which means the she has // given consent to have these services work in touch exploration mode. - final boolean accessibilityEnabled = getIntValueFromTable(db, "secure", + final boolean accessibilityEnabled = getIntValueFromTable(db, TABLE_SECURE, Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; - final boolean touchExplorationEnabled = getIntValueFromTable(db, "secure", + final boolean touchExplorationEnabled = getIntValueFromTable(db, TABLE_SECURE, Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; if (accessibilityEnabled && touchExplorationEnabled) { - String enabledServices = getStringValueFromTable(db, "secure", + String enabledServices = getStringValueFromTable(db, TABLE_SECURE, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); - String touchExplorationGrantedServices = getStringValueFromTable(db, "secure", + String touchExplorationGrantedServices = getStringValueFromTable(db, TABLE_SECURE, Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, ""); if (TextUtils.isEmpty(touchExplorationGrantedServices) && !TextUtils.isEmpty(enabledServices)) { @@ -1137,6 +1174,15 @@ public class DatabaseHelper extends SQLiteOpenHelper { R.string.def_screensaver_component); loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS, R.string.def_screensaver_component); + + // Migrate now-global settings. Note that this happens before + // new users can be created. + createGlobalTable(db); + String[] settingsToMove = (String[]) SettingsProvider.sSystemGlobalKeys.toArray(); + moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove); + settingsToMove = (String[]) SettingsProvider.sSecureGlobalKeys.toArray(); + moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove); + db.setTransactionSuccessful(); } finally { db.endTransaction(); @@ -1162,11 +1208,34 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 82; } + if (upgradeVersion == 82) { + // Move to per-user settings dbs + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + // Migrate now-global settings. Note that this happens before + // new users can be created. + createGlobalTable(db); + String[] settingsToMove = (String[]) SettingsProvider.sSystemGlobalKeys.toArray(); + moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove); + settingsToMove = (String[]) SettingsProvider.sSecureGlobalKeys.toArray(); + moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 83; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion + ", must wipe the settings provider"); + db.execSQL("DROP TABLE IF EXISTS global"); + db.execSQL("DROP TABLE IF EXISTS globalIndex1"); db.execSQL("DROP TABLE IF EXISTS system"); db.execSQL("DROP INDEX IF EXISTS systemIndex1"); db.execSQL("DROP TABLE IF EXISTS secure"); @@ -1187,18 +1256,19 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - private void moveFromSystemToSecure(SQLiteDatabase db, String [] settingsToMove) { - // Copy settings values from 'system' to 'secure' and delete them from 'system' + private void moveSettingsToNewTable(SQLiteDatabase db, + String sourceTable, String destTable, + String[] settingsToMove) { + // Copy settings values from the source table to the dest, and remove from the source SQLiteStatement insertStmt = null; SQLiteStatement deleteStmt = null; db.beginTransaction(); try { - insertStmt = - db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM " - + "system WHERE name=?"); - deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?"); - + insertStmt = db.compileStatement("INSERT INTO " + + destTable + " (name,value) SELECT name,value FROM " + + sourceTable + " WHERE name=?"); + deleteStmt = db.compileStatement("DELETE FROM " + sourceTable + " WHERE name=?"); for (String setting : settingsToMove) { insertStmt.bindString(1, setting); @@ -1220,7 +1290,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } private void upgradeLockPatternLocation(SQLiteDatabase db) { - Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'", + Cursor c = db.query(TABLE_SYSTEM, new String[] {"_id", "value"}, "name='lock_pattern'", null, null, null, null); if (c.getCount() > 0) { c.moveToFirst(); @@ -1237,7 +1307,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } c.close(); - db.delete("system", "name='lock_pattern'", null); + db.delete(TABLE_SYSTEM, "name='lock_pattern'", null); } else { c.close(); } @@ -1245,7 +1315,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { private void upgradeScreenTimeoutFromNever(SQLiteDatabase db) { // See if the timeout is -1 (for "Never"). - Cursor c = db.query("system", new String[] { "_id", "value" }, "name=? AND value=?", + Cursor c = db.query(TABLE_SYSTEM, new String[] { "_id", "value" }, "name=? AND value=?", new String[] { Settings.System.SCREEN_OFF_TIMEOUT, "-1" }, null, null, null); @@ -1514,6 +1584,10 @@ public class DatabaseHelper extends SQLiteOpenHelper { private void loadSettings(SQLiteDatabase db) { loadSystemSettings(db); loadSecureSettings(db); + // The global table only exists for the 'owner' user + if (mUserHandle == UserHandle.USER_OWNER) { + loadGlobalSettings(db); + } } private void loadSystemSettings(SQLiteDatabase db) { @@ -1524,10 +1598,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.System.DIM_SCREEN, R.bool.def_dim_screen); - loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN, - ("1".equals(SystemProperties.get("ro.kernel.qemu")) || - mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in)) - ? 1 : 0); loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT, R.integer.def_screen_off_timeout); @@ -1546,21 +1616,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { // Set default tty mode loadSetting(stmt, Settings.System.TTY_MODE, 0); - loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON, - R.bool.def_airplane_mode_on); - - loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS, - R.string.def_airplane_mode_radios); - - loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS, - R.string.airplane_mode_toggleable_radios); - - loadBooleanSetting(stmt, Settings.System.AUTO_TIME, - R.bool.def_auto_time); // Sync time to NITZ - - loadBooleanSetting(stmt, Settings.System.AUTO_TIME_ZONE, - R.bool.def_auto_time_zone); // Sync timezone to NITZ - loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS, R.integer.def_screen_brightness); @@ -1584,9 +1639,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadIntegerSetting(stmt, Settings.System.POINTER_SPEED, R.integer.def_pointer_speed); - - loadIntegerSetting(stmt, Settings.System.WIFI_SLEEP_POLICY, - R.integer.def_wifi_sleep_policy); } finally { if (stmt != null) stmt.close(); } @@ -1641,39 +1693,12 @@ public class DatabaseHelper extends SQLiteOpenHelper { stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)" + " VALUES(?,?);"); - loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON, - R.bool.def_bluetooth_on); - - // Data roaming default, based on build - loadSetting(stmt, Settings.Secure.DATA_ROAMING, - "true".equalsIgnoreCase( - SystemProperties.get("ro.com.android.dataroaming", - "false")) ? 1 : 0); - - // Mobile Data default, based on build - loadSetting(stmt, Settings.Secure.MOBILE_DATA, - "true".equalsIgnoreCase( - SystemProperties.get("ro.com.android.mobiledata", - "true")) ? 1 : 0); - - loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS, - R.bool.def_install_non_market_apps); - loadBooleanSetting(stmt, Settings.Secure.PACKAGE_VERIFIER_ENABLE, R.bool.def_package_verifier_enable); loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, R.string.def_location_providers_allowed); - loadBooleanSetting(stmt, Settings.Secure.ASSISTED_GPS_ENABLED, - R.bool.assisted_gps_enabled); - - loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE, - R.integer.def_network_preference); - - loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED, - R.bool.def_usb_mass_storage_enabled); - loadBooleanSetting(stmt, Settings.Secure.WIFI_ON, R.bool.def_wifi_on); loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, @@ -1694,10 +1719,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { } loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type); - // Enable or disable Cell Broadcast SMS - loadSetting(stmt, Settings.Secure.CDMA_CELL_BROADCAST_SMS, - RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED); - // Don't do this. The SystemServer will initialize ADB_ENABLED from a // persistent system property instead. //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0); @@ -1726,20 +1747,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS, R.string.def_accessibility_web_content_key_bindings); - final int maxBytes = mContext.getResources().getInteger( - R.integer.def_download_manager_max_bytes_over_mobile); - if (maxBytes > 0) { - loadSetting(stmt, Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE, - Integer.toString(maxBytes)); - } - - final int recommendedMaxBytes = mContext.getResources().getInteger( - R.integer.def_download_manager_recommended_max_bytes_over_mobile); - if (recommendedMaxBytes > 0) { - loadSetting(stmt, Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE, - Integer.toString(recommendedMaxBytes)); - } - loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT, R.integer.def_long_press_timeout_millis); @@ -1759,15 +1766,6 @@ public class DatabaseHelper extends SQLiteOpenHelper { R.bool.def_lockscreen_disabled); } - loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED, - R.bool.def_device_provisioned); - - loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED, - R.bool.def_netstats_enabled); - - loadIntegerSetting(stmt, Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, - R.integer.def_max_dhcp_retries); - loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED, R.bool.def_screensaver_enabled); loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, @@ -1791,6 +1789,97 @@ public class DatabaseHelper extends SQLiteOpenHelper { R.string.def_backup_transport); } + private void loadGlobalSettings(SQLiteDatabase db) { + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)" + + " VALUES(?,?);"); + + // --- Previously in 'system' + loadBooleanSetting(stmt, Settings.Global.AIRPLANE_MODE_ON, + R.bool.def_airplane_mode_on); + + loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_RADIOS, + R.string.def_airplane_mode_radios); + + loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, + R.string.airplane_mode_toggleable_radios); + + loadBooleanSetting(stmt, Settings.Global.ASSISTED_GPS_ENABLED, + R.bool.assisted_gps_enabled); + + loadBooleanSetting(stmt, Settings.Global.AUTO_TIME, + R.bool.def_auto_time); // Sync time to NITZ + + loadBooleanSetting(stmt, Settings.Global.AUTO_TIME_ZONE, + R.bool.def_auto_time_zone); // Sync timezone to NITZ + + loadSetting(stmt, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, + ("1".equals(SystemProperties.get("ro.kernel.qemu")) || + mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in)) + ? 1 : 0); + + loadIntegerSetting(stmt, Settings.Global.WIFI_SLEEP_POLICY, + R.integer.def_wifi_sleep_policy); + + // --- Previously in 'secure' + loadBooleanSetting(stmt, Settings.Global.BLUETOOTH_ON, + R.bool.def_bluetooth_on); + + // Enable or disable Cell Broadcast SMS + loadSetting(stmt, Settings.Global.CDMA_CELL_BROADCAST_SMS, + RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED); + + // Data roaming default, based on build + loadSetting(stmt, Settings.Global.DATA_ROAMING, + "true".equalsIgnoreCase( + SystemProperties.get("ro.com.android.dataroaming", + "false")) ? 1 : 0); + + loadBooleanSetting(stmt, Settings.Global.DEVICE_PROVISIONED, + R.bool.def_device_provisioned); + + final int maxBytes = mContext.getResources().getInteger( + R.integer.def_download_manager_max_bytes_over_mobile); + if (maxBytes > 0) { + loadSetting(stmt, Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE, + Integer.toString(maxBytes)); + } + + final int recommendedMaxBytes = mContext.getResources().getInteger( + R.integer.def_download_manager_recommended_max_bytes_over_mobile); + if (recommendedMaxBytes > 0) { + loadSetting(stmt, Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE, + Integer.toString(recommendedMaxBytes)); + } + + // Mobile Data default, based on build + loadSetting(stmt, Settings.Global.MOBILE_DATA, + "true".equalsIgnoreCase( + SystemProperties.get("ro.com.android.mobiledata", + "true")) ? 1 : 0); + + loadBooleanSetting(stmt, Settings.Global.NETSTATS_ENABLED, + R.bool.def_netstats_enabled); + + loadBooleanSetting(stmt, Settings.Global.INSTALL_NON_MARKET_APPS, + R.bool.def_install_non_market_apps); + + loadIntegerSetting(stmt, Settings.Global.NETWORK_PREFERENCE, + R.integer.def_network_preference); + + loadBooleanSetting(stmt, Settings.Global.USB_MASS_STORAGE_ENABLED, + R.bool.def_usb_mass_storage_enabled); + + loadIntegerSetting(stmt, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, + R.integer.def_max_dhcp_retries); + + // --- New global settings start here + } finally { + if (stmt != null) stmt.close(); + } + } + private void loadSetting(SQLiteStatement stmt, String key, Object value) { stmt.bindString(1, key); stmt.bindString(2, value.toString()); @@ -1817,7 +1906,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } private int getIntValueFromSystem(SQLiteDatabase db, String name, int defaultValue) { - return getIntValueFromTable(db, "system", name, defaultValue); + return getIntValueFromTable(db, TABLE_SYSTEM, name, defaultValue); } private int getIntValueFromTable(SQLiteDatabase db, String table, String name, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 1fa369566d07f..b444eb15d3f7c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -18,53 +18,73 @@ package com.android.providers.settings; import java.io.FileNotFoundException; import java.security.SecureRandom; +import java.util.HashSet; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import android.app.ActivityManagerNative; import android.app.backup.BackupManager; +import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteQueryBuilder; +import android.database.sqlite.SQLiteStatement; import android.media.RingtoneManager; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.FileObserver; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; +import android.os.UserManager; import android.provider.DrmStore; import android.provider.MediaStore; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.LruCache; +import android.util.Slog; +import android.util.SparseArray; public class SettingsProvider extends ContentProvider { private static final String TAG = "SettingsProvider"; private static final boolean LOCAL_LOGV = false; + private static final String TABLE_SYSTEM = "system"; + private static final String TABLE_SECURE = "secure"; + private static final String TABLE_GLOBAL = "global"; private static final String TABLE_FAVORITES = "favorites"; private static final String TABLE_OLD_FAVORITES = "old_favorites"; private static final String[] COLUMN_VALUE = new String[] { "value" }; - // Cache for settings, access-ordered for acting as LRU. + // Caches for each user's settings, access-ordered for acting as LRU. // Guarded by themselves. private static final int MAX_CACHE_ENTRIES = 200; - private static final SettingsCache sSystemCache = new SettingsCache("system"); - private static final SettingsCache sSecureCache = new SettingsCache("secure"); + private static final SparseArray sSystemCaches + = new SparseArray(); + private static final SparseArray sSecureCaches + = new SparseArray(); + private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL); // The count of how many known (handled by SettingsProvider) - // database mutations are currently being handled. Used by - // sFileObserver to not reload the database when it's ourselves + // database mutations are currently being handled for this user. + // Used by file observers to not reload the database when it's ourselves // modifying it. - private static final AtomicInteger sKnownMutationsInFlight = new AtomicInteger(0); + private static final SparseArray sKnownMutationsInFlight + = new SparseArray(); // Over this size we don't reject loading or saving settings but // we do consider them broken/malicious and don't keep them in @@ -77,9 +97,130 @@ public class SettingsProvider extends ContentProvider { // want to cache the existence of a key, but not store its value. private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null); - protected DatabaseHelper mOpenHelper; + // Each defined user has their own settings + protected final SparseArray mOpenHelpers = new SparseArray(); + //protected DatabaseHelper mOpenHelper; + private UserManager mUserManager; private BackupManager mBackupManager; + /** + * Settings which need to be treated as global/shared in multi-user environments. + */ + static final HashSet sSecureGlobalKeys; + static final HashSet sSystemGlobalKeys; + static { + // Keys (name column) from the 'secure' table that are now in the owner user's 'global' + // table, shared across all users + // These must match Settings.Secure.MOVED_TO_GLOBAL + sSecureGlobalKeys = new HashSet(); + sSecureGlobalKeys.add(Settings.Secure.ASSISTED_GPS_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.CDMA_CELL_BROADCAST_SMS); + sSecureGlobalKeys.add(Settings.Secure.CDMA_ROAMING_MODE); + sSecureGlobalKeys.add(Settings.Secure.CDMA_SUBSCRIPTION_MODE); + sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE); + sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI); + sSecureGlobalKeys.add(Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.DISPLAY_DENSITY_FORCED); + sSecureGlobalKeys.add(Settings.Secure.DISPLAY_SIZE_FORCED); + sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE); + sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE); + sSecureGlobalKeys.add(Settings.Secure.MOBILE_DATA); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_BUCKET_DURATION); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_DELETE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_PERSIST_BYTES); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_ROTATE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_POLL_INTERVAL); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_SAMPLE_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_BUCKET_DURATION); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_DELETE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_PERSIST_BYTES); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_ROTATE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_BUCKET_DURATION); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_DELETE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_PERSIST_BYTES); + sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_ROTATE_AGE); + sSecureGlobalKeys.add(Settings.Secure.NETWORK_PREFERENCE); + sSecureGlobalKeys.add(Settings.Secure.NITZ_UPDATE_DIFF); + sSecureGlobalKeys.add(Settings.Secure.NITZ_UPDATE_SPACING); + sSecureGlobalKeys.add(Settings.Secure.NTP_SERVER); + sSecureGlobalKeys.add(Settings.Secure.NTP_TIMEOUT); + sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_ERROR_POLL_COUNT); + sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS); + sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT); + sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS); + sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT); + sSecureGlobalKeys.add(Settings.Secure.SAMPLING_PROFILER_MS); + sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL); + sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DETECTION_REDIR_HOST); + sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DETECTION_TARGET_URL); + sSecureGlobalKeys.add(Settings.Secure.TETHER_DUN_APN); + sSecureGlobalKeys.add(Settings.Secure.TETHER_DUN_REQUIRED); + sSecureGlobalKeys.add(Settings.Secure.TETHER_SUPPORTED); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_HELP_URI); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_NOTIFICATION_TYPE); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_POLLING_SEC); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_RESET_DAY); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_THRESHOLD_BYTES); + sSecureGlobalKeys.add(Settings.Secure.THROTTLE_VALUE_KBITSPS); + sSecureGlobalKeys.add(Settings.Secure.USE_GOOGLE_MAIL); + sSecureGlobalKeys.add(Settings.Secure.WEB_AUTOFILL_QUERY_URL); + sSecureGlobalKeys.add(Settings.Secure.WIFI_COUNTRY_CODE); + sSecureGlobalKeys.add(Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS); + sSecureGlobalKeys.add(Settings.Secure.WIFI_FREQUENCY_BAND); + sSecureGlobalKeys.add(Settings.Secure.WIFI_IDLE_MS); + sSecureGlobalKeys.add(Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT); + sSecureGlobalKeys.add(Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS); + sSecureGlobalKeys.add(Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); + sSecureGlobalKeys.add(Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY); + sSecureGlobalKeys.add(Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT); + sSecureGlobalKeys.add(Settings.Secure.WIFI_ON); + sSecureGlobalKeys.add(Settings.Secure.WIFI_P2P_DEVICE_NAME); + sSecureGlobalKeys.add(Settings.Secure.WIFI_SAVED_STATE); + sSecureGlobalKeys.add(Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS); + sSecureGlobalKeys.add(Settings.Secure.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_NUM_ARP_PINGS); + sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_ON); + sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED); + sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS); + sSecureGlobalKeys.add(Settings.Secure.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON); + sSecureGlobalKeys.add(Settings.Secure.WTF_IS_FATAL); + + // Keys from the 'system' table now moved to 'global' + // These must match Settings.System.MOVED_TO_GLOBAL + sSystemGlobalKeys = new HashSet(); + sSystemGlobalKeys.add(Settings.Secure.ADB_ENABLED); + sSystemGlobalKeys.add(Settings.Secure.BLUETOOTH_ON); + sSystemGlobalKeys.add(Settings.Secure.DATA_ROAMING); + sSystemGlobalKeys.add(Settings.Secure.DEVICE_PROVISIONED); + sSystemGlobalKeys.add(Settings.Secure.INSTALL_NON_MARKET_APPS); + sSystemGlobalKeys.add(Settings.Secure.USB_MASS_STORAGE_ENABLED); + + sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_ON); + sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_RADIOS); + sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); + sSystemGlobalKeys.add(Settings.System.AUTO_TIME); + sSystemGlobalKeys.add(Settings.System.AUTO_TIME_ZONE); + sSystemGlobalKeys.add(Settings.System.CAR_DOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.CAR_UNDOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.DESK_DOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.DESK_UNDOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.DOCK_SOUNDS_ENABLED); + sSystemGlobalKeys.add(Settings.System.LOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.UNLOCK_SOUND); + sSystemGlobalKeys.add(Settings.System.LOW_BATTERY_SOUND); + sSystemGlobalKeys.add(Settings.System.POWER_SOUNDS_ENABLED); + sSystemGlobalKeys.add(Settings.System.WIFI_SLEEP_POLICY); + } + + private boolean settingMovedToGlobal(final String name) { + return sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name); + } + /** * Decode a content URL into the table, projection, and arguments * used to access the corresponding database rows. @@ -107,7 +248,7 @@ public class SettingsProvider extends ContentProvider { if (!DatabaseHelper.isValidTable(this.table)) { throw new IllegalArgumentException("Bad root path: " + this.table); } - if ("system".equals(this.table) || "secure".equals(this.table)) { + if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table)) { this.where = Settings.NameValueTable.NAME + "=?"; this.args = new String[] { url.getPathSegments().get(1) }; } else { @@ -144,7 +285,9 @@ public class SettingsProvider extends ContentProvider { throw new IllegalArgumentException("Invalid URI: " + tableUri); } String table = tableUri.getPathSegments().get(0); - if ("system".equals(table) || "secure".equals(table)) { + if (TABLE_SYSTEM.equals(table) || + TABLE_SECURE.equals(table) || + TABLE_GLOBAL.equals(table)) { String name = values.getAsString(Settings.NameValueTable.NAME); return Uri.withAppendedPath(tableUri, name); } else { @@ -159,18 +302,21 @@ public class SettingsProvider extends ContentProvider { * contract class uses these to provide client-side caches.) * @param uri to send notifications for */ - private void sendNotify(Uri uri) { + private void sendNotify(Uri uri, int userHandle) { // Update the system property *first*, so if someone is listening for // a notification and then using the contract class to get their data, // the system property will be updated and they'll get the new data. boolean backedUpDataChanged = false; String property = null, table = uri.getPathSegments().get(0); - if (table.equals("system")) { - property = Settings.System.SYS_PROP_SETTING_VERSION; + if (table.equals(TABLE_SYSTEM)) { + property = Settings.System.SYS_PROP_SETTING_VERSION + '_' + userHandle; backedUpDataChanged = true; - } else if (table.equals("secure")) { - property = Settings.Secure.SYS_PROP_SETTING_VERSION; + } else if (table.equals(TABLE_SECURE)) { + property = Settings.Secure.SYS_PROP_SETTING_VERSION + '_' + userHandle; + backedUpDataChanged = true; + } else if (table.equals(TABLE_GLOBAL)) { + property = Settings.Global.SYS_PROP_SETTING_VERSION; // this one is global backedUpDataChanged = true; } @@ -201,7 +347,7 @@ public class SettingsProvider extends ContentProvider { * @throws SecurityException if the caller is forbidden to write. */ private void checkWritePermissions(SqlArguments args) { - if ("secure".equals(args.table) && + if ((TABLE_SECURE.equals(args.table) || TABLE_GLOBAL.equals(args.table)) && getContext().checkCallingOrSelfPermission( android.Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) { @@ -218,70 +364,147 @@ public class SettingsProvider extends ContentProvider { // normally the exclusive owner of the database. But we keep this // enabled all the time to minimize development-vs-user // differences in testing. - private static SettingsFileObserver sObserverInstance; + private static SparseArray sObserverInstances + = new SparseArray(); private class SettingsFileObserver extends FileObserver { private final AtomicBoolean mIsDirty = new AtomicBoolean(false); + private final int mUserHandle; private final String mPath; - public SettingsFileObserver(String path) { + public SettingsFileObserver(int userHandle, String path) { super(path, FileObserver.CLOSE_WRITE | FileObserver.CREATE | FileObserver.DELETE | FileObserver.MOVED_TO | FileObserver.MODIFY); + mUserHandle = userHandle; mPath = path; } public void onEvent(int event, String path) { - int modsInFlight = sKnownMutationsInFlight.get(); + int modsInFlight = sKnownMutationsInFlight.get(mUserHandle).get(); if (modsInFlight > 0) { // our own modification. return; } - Log.d(TAG, "external modification to " + mPath + "; event=" + event); + Log.d(TAG, "User " + mUserHandle + " external modification to " + mPath + + "; event=" + event); if (!mIsDirty.compareAndSet(false, true)) { // already handled. (we get a few update events // during an sqlite write) return; } - Log.d(TAG, "updating our caches for " + mPath); - fullyPopulateCaches(); + Log.d(TAG, "User " + mUserHandle + " updating our caches for " + mPath); + fullyPopulateCaches(mUserHandle); mIsDirty.set(false); } } @Override public boolean onCreate() { - mOpenHelper = new DatabaseHelper(getContext()); mBackupManager = new BackupManager(getContext()); + mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); - if (!ensureAndroidIdIsSet()) { - return false; + synchronized (this) { + establishDbTrackingLocked(UserHandle.USER_OWNER); + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) { + final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + UserHandle.USER_OWNER); + if (userHandle != UserHandle.USER_OWNER) { + onUserRemoved(userHandle); + } + } + } + }, userFilter); + + if (!ensureAndroidIdIsSet()) { + return false; + } } - - // Watch for external modifications to the database file, - // keeping our cache in sync. - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - sObserverInstance = new SettingsFileObserver(db.getPath()); - sObserverInstance.startWatching(); - startAsyncCachePopulation(); return true; } - private void startAsyncCachePopulation() { - new Thread("populate-settings-caches") { - public void run() { - fullyPopulateCaches(); + void onUserRemoved(int userHandle) { + // the db file itself will be deleted automatically, but we need to tear down + // our caches and other internal bookkeeping. Creation/deletion of a user's + // settings db infrastructure is synchronized on 'this' + synchronized (this) { + FileObserver observer = sObserverInstances.get(userHandle); + if (observer != null) { + observer.stopWatching(); + sObserverInstances.delete(userHandle); } - }.start(); + + mOpenHelpers.delete(userHandle); + sSystemCaches.delete(userHandle); + sSecureCaches.delete(userHandle); + sKnownMutationsInFlight.delete(userHandle); + + String property = Settings.System.SYS_PROP_SETTING_VERSION + '_' + userHandle; + SystemProperties.set(property, ""); + property = Settings.Secure.SYS_PROP_SETTING_VERSION + '_' + userHandle; + SystemProperties.set(property, ""); + } } - private void fullyPopulateCaches() { - fullyPopulateCache("secure", sSecureCache); - fullyPopulateCache("system", sSystemCache); + private void establishDbTrackingLocked(int userHandle) { + if (LOCAL_LOGV) { + Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle); + } + + DatabaseHelper dbhelper = new DatabaseHelper(getContext(), userHandle); + mOpenHelpers.append(userHandle, dbhelper); + + // Watch for external modifications to the database files, + // keeping our caches in sync. + sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM)); + sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE)); + sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0)); + SQLiteDatabase db = dbhelper.getWritableDatabase(); + + // Now we can start observing it for changes + SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath()); + sObserverInstances.append(userHandle, observer); + observer.startWatching(); + + startAsyncCachePopulation(userHandle); + } + + class CachePrefetchThread extends Thread { + private int mUserHandle; + + CachePrefetchThread(int userHandle) { + super("populate-settings-caches"); + mUserHandle = userHandle; + } + + @Override + public void run() { + fullyPopulateCaches(mUserHandle); + } + } + + private void startAsyncCachePopulation(int userHandle) { + new CachePrefetchThread(userHandle).start(); + } + + private void fullyPopulateCaches(final int userHandle) { + DatabaseHelper dbHelper = mOpenHelpers.get(userHandle); + // Only populate the globals cache once, for the owning user + if (userHandle == UserHandle.USER_OWNER) { + fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache); + } + fullyPopulateCache(dbHelper, TABLE_SECURE, sSecureCaches.get(userHandle)); + fullyPopulateCache(dbHelper, TABLE_SYSTEM, sSystemCaches.get(userHandle)); } // Slurp all values (if sane in number & size) into cache. - private void fullyPopulateCache(String table, SettingsCache cache) { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + private void fullyPopulateCache(DatabaseHelper dbHelper, String table, SettingsCache cache) { + SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor c = db.query( table, new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE }, @@ -337,23 +560,154 @@ public class SettingsProvider extends ContentProvider { } } + // Lazy-initialize the settings caches for non-primary users + private SettingsCache getOrConstructCache(int callingUser, SparseArray which) { + synchronized (this) { + getOrEstablishDatabaseLocked(callingUser); // ignore return value; we don't need it + return which.get(callingUser); + } + } + + // Lazy initialize the database helper and caches for this user, if necessary + private DatabaseHelper getOrEstablishDatabaseLocked(int callingUser) { + long oldId = Binder.clearCallingIdentity(); + try { + DatabaseHelper dbHelper = mOpenHelpers.get(callingUser); + if (null == dbHelper) { + establishDbTrackingLocked(callingUser); + dbHelper = mOpenHelpers.get(callingUser); + } + return dbHelper; + } finally { + Binder.restoreCallingIdentity(oldId); + } + } + + public SettingsCache cacheForTable(final int callingUser, String tableName) { + if (TABLE_SYSTEM.equals(tableName)) { + return getOrConstructCache(callingUser, sSystemCaches); + } + if (TABLE_SECURE.equals(tableName)) { + return getOrConstructCache(callingUser, sSecureCaches); + } + if (TABLE_GLOBAL.equals(tableName)) { + return sGlobalCache; + } + return null; + } + + /** + * Used for wiping a whole cache on deletes when we're not + * sure what exactly was deleted or changed. + */ + public void invalidateCache(final int callingUser, String tableName) { + SettingsCache cache = cacheForTable(callingUser, tableName); + if (cache == null) { + return; + } + synchronized (cache) { + cache.evictAll(); + cache.mCacheFullyMatchesDisk = false; + } + } + /** * Fast path that avoids the use of chatty remoted Cursors. */ @Override public Bundle call(String method, String request, Bundle args) { + int callingUser = UserHandle.getCallingUserId(); + if (args != null) { + int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser); + if (reqUser != callingUser) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "Not permitted to access settings for other users"); + if (reqUser == UserHandle.USER_CURRENT) { + try { + reqUser = ActivityManagerNative.getDefault().getCurrentUser().id; + } catch (RemoteException e) { + // can't happen + } + if (LOCAL_LOGV) { + Slog.v(TAG, " USER_CURRENT resolved to " + reqUser); + } + } + if (reqUser < 0) { + throw new IllegalArgumentException("Bad user handle " + reqUser); + } + callingUser = reqUser; + if (LOCAL_LOGV) Slog.v(TAG, " fetching setting for user " + callingUser); + } + } + + // Note: we assume that get/put operations for moved-to-global names have already + // been directed to the new location on the caller side (otherwise we'd fix them + // up here). + + DatabaseHelper dbHelper; + SettingsCache cache; + + // Get methods if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) { - return lookupValue("system", sSystemCache, request); + if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser); + synchronized (this) { + dbHelper = getOrEstablishDatabaseLocked(callingUser); + cache = sSystemCaches.get(callingUser); + } + return lookupValue(dbHelper, TABLE_SYSTEM, cache, request); } if (Settings.CALL_METHOD_GET_SECURE.equals(method)) { - return lookupValue("secure", sSecureCache, request); + if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser); + synchronized (this) { + dbHelper = getOrEstablishDatabaseLocked(callingUser); + cache = sSecureCaches.get(callingUser); + } + return lookupValue(dbHelper, TABLE_SECURE, cache, request); } + if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) { + if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser); + // fast path: owner db & cache are immutable after onCreate() so we need not + // guard on the attempt to look them up + return lookupValue(getOrEstablishDatabaseLocked(UserHandle.USER_OWNER), TABLE_GLOBAL, + sGlobalCache, request); + } + + // Put methods - new value is in the args bundle under the key named by + // the Settings.NameValueTable.VALUE static. + final String newValue = (args == null) + ? null : args.getString(Settings.NameValueTable.VALUE); + if (newValue == null) { + throw new IllegalArgumentException("Bad value for " + method); + } + + final ContentValues values = new ContentValues(); + values.put(Settings.NameValueTable.NAME, request); + values.put(Settings.NameValueTable.VALUE, newValue); + if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) { + if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser); + insert(Settings.System.CONTENT_URI, values); + } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) { + if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser); + insert(Settings.Secure.CONTENT_URI, values); + } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) { + if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser); + insert(Settings.Global.CONTENT_URI, values); + } else { + Slog.w(TAG, "call() with invalid method: " + method); + } + return null; } // Looks up value 'key' in 'table' and returns either a single-pair Bundle, // possibly with a null value, or null on failure. - private Bundle lookupValue(String table, SettingsCache cache, String key) { + private Bundle lookupValue(DatabaseHelper dbHelper, String table, + final SettingsCache cache, String key) { + if (cache == null) { + Slog.e(TAG, "cache is null for user " + UserHandle.getCallingUserId() + " : key=" + key); + return null; + } synchronized (cache) { Bundle value = cache.get(key); if (value != null) { @@ -372,7 +726,7 @@ public class SettingsProvider extends ContentProvider { } } - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; try { cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key}, @@ -393,8 +747,14 @@ public class SettingsProvider extends ContentProvider { @Override public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) { + final int callingUser = UserHandle.getCallingUserId(); + if (LOCAL_LOGV) Slog.v(TAG, "query() for user " + callingUser); SqlArguments args = new SqlArguments(url, where, whereArgs); - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + DatabaseHelper dbH; + synchronized (this) { + dbH = getOrEstablishDatabaseLocked(callingUser); + } + SQLiteDatabase db = dbH.getReadableDatabase(); // The favorites table was moved from this provider to a provider inside Home // Home still need to query this table to upgrade from pre-cupcake builds @@ -437,15 +797,22 @@ public class SettingsProvider extends ContentProvider { @Override public int bulkInsert(Uri uri, ContentValues[] values) { + final int callingUser = UserHandle.getCallingUserId(); + if (LOCAL_LOGV) Slog.v(TAG, "bulkInsert() for user " + callingUser); SqlArguments args = new SqlArguments(uri); if (TABLE_FAVORITES.equals(args.table)) { return 0; } checkWritePermissions(args); - SettingsCache cache = SettingsCache.forTable(args.table); + SettingsCache cache = cacheForTable(callingUser, args.table); - sKnownMutationsInFlight.incrementAndGet(); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser); + mutationCount.incrementAndGet(); + DatabaseHelper dbH; + synchronized (this) { + dbH = getOrEstablishDatabaseLocked(callingUser); + } + SQLiteDatabase db = dbH.getWritableDatabase(); db.beginTransaction(); try { int numValues = values.length; @@ -457,10 +824,10 @@ public class SettingsProvider extends ContentProvider { db.setTransactionSuccessful(); } finally { db.endTransaction(); - sKnownMutationsInFlight.decrementAndGet(); + mutationCount.decrementAndGet(); } - sendNotify(uri); + sendNotify(uri, callingUser); return values.length; } @@ -538,6 +905,22 @@ public class SettingsProvider extends ContentProvider { @Override public Uri insert(Uri url, ContentValues initialValues) { + return insertForUser(url, initialValues, UserHandle.getCallingUserId()); + } + + // Settings.put*ForUser() always winds up here, so this is where we apply + // policy around permission to write settings for other users. + private Uri insertForUser(Uri url, ContentValues initialValues, int desiredUserHandle) { + final int callingUser = UserHandle.getCallingUserId(); + if (callingUser != desiredUserHandle) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + "Not permitted to access settings for other users"); + } + + if (LOCAL_LOGV) Slog.v(TAG, "insert(" + url + ") for user " + desiredUserHandle + + " by " + callingUser); + SqlArguments args = new SqlArguments(url); if (TABLE_FAVORITES.equals(args.table)) { return null; @@ -551,28 +934,41 @@ public class SettingsProvider extends ContentProvider { if (!parseProviderList(url, initialValues)) return null; } - SettingsCache cache = SettingsCache.forTable(args.table); + // The global table is stored under the owner, always + if (TABLE_GLOBAL.equals(args.table)) { + desiredUserHandle = UserHandle.USER_OWNER; + } + + SettingsCache cache = cacheForTable(desiredUserHandle, args.table); String value = initialValues.getAsString(Settings.NameValueTable.VALUE); if (SettingsCache.isRedundantSetValue(cache, name, value)) { return Uri.withAppendedPath(url, name); } - sKnownMutationsInFlight.incrementAndGet(); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final AtomicInteger mutationCount = sKnownMutationsInFlight.get(desiredUserHandle); + mutationCount.incrementAndGet(); + DatabaseHelper dbH; + synchronized (this) { + dbH = getOrEstablishDatabaseLocked(callingUser); + } + SQLiteDatabase db = dbH.getWritableDatabase(); final long rowId = db.insert(args.table, null, initialValues); - sKnownMutationsInFlight.decrementAndGet(); + mutationCount.decrementAndGet(); if (rowId <= 0) return null; SettingsCache.populate(cache, initialValues); // before we notify if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues); + // Note that we use the original url here, not the potentially-rewritten table name url = getUriFor(url, initialValues, rowId); - sendNotify(url); + sendNotify(url, desiredUserHandle); return url; } @Override public int delete(Uri url, String where, String[] whereArgs) { + final int callingUser = UserHandle.getCallingUserId(); + if (LOCAL_LOGV) Slog.v(TAG, "delete() for user " + callingUser); SqlArguments args = new SqlArguments(url, where, whereArgs); if (TABLE_FAVORITES.equals(args.table)) { return 0; @@ -581,36 +977,53 @@ public class SettingsProvider extends ContentProvider { } checkWritePermissions(args); - sKnownMutationsInFlight.incrementAndGet(); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count = db.delete(args.table, args.where, args.args); - sKnownMutationsInFlight.decrementAndGet(); - if (count > 0) { - SettingsCache.invalidate(args.table); // before we notify - sendNotify(url); + final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser); + mutationCount.incrementAndGet(); + DatabaseHelper dbH; + synchronized (this) { + dbH = getOrEstablishDatabaseLocked(callingUser); } - startAsyncCachePopulation(); + SQLiteDatabase db = dbH.getWritableDatabase(); + int count = db.delete(args.table, args.where, args.args); + mutationCount.decrementAndGet(); + if (count > 0) { + invalidateCache(callingUser, args.table); // before we notify + sendNotify(url, callingUser); + } + startAsyncCachePopulation(callingUser); if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted"); return count; } @Override public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) { + // NOTE: update() is never called by the front-end Settings API, and updates that + // wind up affecting rows in Secure that are globally shared will not have the + // intended effect (the update will be invisible to the rest of the system). + // This should have no practical effect, since writes to the Secure db can only + // be done by system code, and that code should be using the correct API up front. + final int callingUser = UserHandle.getCallingUserId(); + if (LOCAL_LOGV) Slog.v(TAG, "update() for user " + callingUser); SqlArguments args = new SqlArguments(url, where, whereArgs); if (TABLE_FAVORITES.equals(args.table)) { return 0; } checkWritePermissions(args); - sKnownMutationsInFlight.incrementAndGet(); - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count = db.update(args.table, initialValues, args.where, args.args); - sKnownMutationsInFlight.decrementAndGet(); - if (count > 0) { - SettingsCache.invalidate(args.table); // before we notify - sendNotify(url); + final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser); + mutationCount.incrementAndGet(); + DatabaseHelper dbH; + synchronized (this) { + dbH = getOrEstablishDatabaseLocked(callingUser); } - startAsyncCachePopulation(); + SQLiteDatabase db = dbH.getWritableDatabase(); + int count = db.update(args.table, initialValues, args.where, args.args); + mutationCount.decrementAndGet(); + if (count > 0) { + invalidateCache(callingUser, args.table); // before we notify + sendNotify(url, callingUser); + } + startAsyncCachePopulation(callingUser); if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues); return count; } @@ -772,16 +1185,6 @@ public class SettingsProvider extends ContentProvider { return bundle; } - public static SettingsCache forTable(String tableName) { - if ("system".equals(tableName)) { - return SettingsProvider.sSystemCache; - } - if ("secure".equals(tableName)) { - return SettingsProvider.sSecureCache; - } - return null; - } - /** * Populates a key in a given (possibly-null) cache. */ @@ -808,21 +1211,6 @@ public class SettingsProvider extends ContentProvider { } } - /** - * Used for wiping a whole cache on deletes when we're not - * sure what exactly was deleted or changed. - */ - public static void invalidate(String tableName) { - SettingsCache cache = SettingsCache.forTable(tableName); - if (cache == null) { - return; - } - synchronized (cache) { - cache.evictAll(); - cache.mCacheFullyMatchesDisk = false; - } - } - /** * For suppressing duplicate/redundant settings inserts early, * checking our cache first (but without faulting it in),