Per-user settings

Each user has its own Settings.System.* and Settings.Secure.* namespace now.  In
addition, this CL introduces the new Settings.Global.* namespace, which contains
a number of previously-elsewhere named settings entities; these Global.* entities
are common to all users.  Because these elements have been moved from their prior
existence in the other namespaces, attempts to access them under their old names
and namespaces are detected and redirected (with appropriate compile-time and
logging messages) to their new homes.

The new Global.* namespace can only be written by system-level code, just like
the existing Secure.* namespace.  If an app attempts to write a key that was
previously in the System.* namespace but has been moved to the Global.* namespace,
then a warning is logged and no write is performed; the action is a no-op.  (The
app is explicitly not crashed, to avoid breaking well-behaved apps that can't
know any better.)

There is also now a hidden API for getting/setting settings entities associated
with a user other than the caller's.  Reading/writing data for a user other than
yourself requires the signature-level INTERACT_ACROSS_USERS_FULL permission.

Manipulating data for a different user cannot be done via the ContentProvider
query() / insert() APIs; you must use the Settings.get/put APIs for that degree
of control.  In general, use of the get/set API is *strongly* preferred over
query-type access to Settings.

Bug 6985398

Change-Id: Ibee54ddff99fb847c8c2479c23b50f1e7524d724
diff --git a/api/current.txt b/api/current.txt
index ee21360..0f5fd35 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18718,6 +18718,53 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 1b0c775..6b4bc76 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -621,6 +621,25 @@
     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.
      * <p>
      * This can be passed as an extra field in an Activity Intent with one or more syncable content
@@ -640,7 +659,7 @@
     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 @@
 
         // 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 @@
                 }
             }
 
-            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 @@
                 if (c != null) c.close();
             }
         }
+
+        public String getString(ContentResolver cr, String name) {
+            return getStringForUser(cr, name, UserHandle.myUserId());
+        }
     }
 
     /**
@@ -791,13 +845,8 @@
         private static final HashSet<String> MOVED_TO_SECURE;
         static {
             MOVED_TO_SECURE = new HashSet<String>(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 @@
             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 @@
             MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS);
         }
 
+        private static final HashSet<String> MOVED_TO_GLOBAL;
+        static {
+            MOVED_TO_GLOBAL = new HashSet<String>();
+            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 @@
          * @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 @@
          * @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 @@
                     + " 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 @@
          * 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 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 @@
          * @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 @@
          * 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 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 @@
          * @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 @@
          * 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 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 @@
          * @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 @@
          * @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 @@
          * @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 @@
             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 @@
             Uri.parse("content://" + AUTHORITY + "/system");
 
         /**
-         * Whether we keep the device on while the device is plugged in.
-         * Supported values are:
-         * <ul>
-         * <li>{@code 0} to never stay on while plugged in</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_WIRELESS} to stay on for wireless charger</li>
-         * </ul>
-         * 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 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).
-         * <p>
-         * 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 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 @@
                 "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 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 @@
         // 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 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 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 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 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 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 @@
 
         private static boolean sIsSystemProcess;
         private static final HashSet<String> MOVED_TO_LOCK_SETTINGS;
+        private static final HashSet<String> MOVED_TO_GLOBAL;
         static {
             MOVED_TO_LOCK_SETTINGS = new HashSet<String>(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<String>();
+            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 @@
          * @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 @@
             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 @@
          * @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 @@
          * @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 @@
          * 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 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 @@
          * @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 @@
          * 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 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 @@
          * @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 @@
          * 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 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 @@
          * @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 @@
             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 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 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 @@
         }
 
         /**
-         * 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 @@
                 "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 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 @@
             "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 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 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 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 @@
                 "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 @@
                 = "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 @@
 
 
         /**
-         * 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 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 @@
                 "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 @@
                 "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 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 @@
                 "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 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
@@ -4451,6 +4865,955 @@
     }
 
     /**
+     * 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).
+         * <p>
+         * 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:
+         * <ul>
+         * <li>{@code 0} to never stay on while plugged in</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_WIRELESS} to stay on for wireless charger</li>
+         * </ul>
+         * 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.
+        * <p>
+        * 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.
+         * <p>
+         * 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.
+         * <p>
+         * 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.
+         * <p>
+         * 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
      * application activity.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 9c41119..1be363f 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.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 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 @@
     // 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<String> mValidTables = new HashSet<String>();
 
+    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 @@
         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 @@
         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 @@
 
         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 @@
                     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 @@
                    "lockscreen.lockedoutpermanently",
                    "lockscreen.password_salt"
            };
-           moveFromSystemToSecure(db, settingsToMove);
+           moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove);
            upgradeVersion = 52;
        }
 
@@ -687,7 +724,7 @@
                     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 @@
             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 @@
             // 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 @@
                         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 @@
             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 @@
         }
     }
 
-    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 @@
     }
 
     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 @@
                 }
             }
             c.close();
-            db.delete("system", "name='lock_pattern'", null);
+            db.delete(TABLE_SYSTEM, "name='lock_pattern'", null);
         } else {
             c.close();
         }
@@ -1245,7 +1315,7 @@
 
     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 @@
     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 @@
 
             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 @@
             // 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 @@
 
             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 @@
             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 @@
             }
             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 @@
             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 @@
                         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 @@
                 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 @@
     }
 
     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 1fa3695..b444eb1 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 @@
 
 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<SettingsCache> sSystemCaches
+            = new SparseArray<SettingsCache>();
+    private static final SparseArray<SettingsCache> sSecureCaches
+            = new SparseArray<SettingsCache>();
+    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<AtomicInteger> sKnownMutationsInFlight
+            = new SparseArray<AtomicInteger>();
 
     // 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,10 +97,131 @@
     // 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<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
+    //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<String> sSecureGlobalKeys;
+    static final HashSet<String> 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<String>();
+        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<String>();
+        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 @@
                 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 @@
             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 @@
      * 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 @@
      * @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 @@
     // 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<SettingsFileObserver> sObserverInstances
+            = new SparseArray<SettingsFileObserver>();
     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 @@
         }
     }
 
+    // Lazy-initialize the settings caches for non-primary users
+    private SettingsCache getOrConstructCache(int callingUser, SparseArray<SettingsCache> 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 @@
             }
         }
 
-        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 @@
 
     @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 @@
 
     @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 @@
             db.setTransactionSuccessful();
         } finally {
             db.endTransaction();
-            sKnownMutationsInFlight.decrementAndGet();
+            mutationCount.decrementAndGet();
         }
 
-        sendNotify(uri);
+        sendNotify(uri, callingUser);
         return values.length;
     }
 
@@ -538,6 +905,22 @@
 
     @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 @@
             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 @@
         }
         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 @@
             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.
          */
@@ -809,21 +1212,6 @@
         }
 
         /**
-         * 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),
          * before going to sqlite with the mutation.