Merge "Monkey should not be allowed to switch USB mode" into mnc-dev
diff --git a/res/layout/manage_assist_footer.xml b/res/layout/manage_assist_footer.xml
new file mode 100644
index 0000000..8e10d62
--- /dev/null
+++ b/res/layout/manage_assist_footer.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@android:style/TextAppearance.Material.Body1"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:textColor="?android:attr/textColorSecondary"
+    android:paddingTop="16dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:paddingBottom="16dp"
+    android:selectable="false"
+    android:clickable="false"
+    android:text="@string/assist_footer">
+</TextView>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e4e9255..646c385 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -207,7 +207,9 @@
     <integer name="bluetooth_name_length">32</integer>
     <dimen name="bluetooth_pairing_padding">20dp</dimen>
 
+    <!-- WiFi Preferences -->
     <dimen name="wifi_divider_height">1px</dimen>
+    <dimen name="wifi_preference_badge_padding">8dip</dimen>
 
     <!-- Color picker -->
     <dimen name="color_swatch_size">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0e2ed8f..feb10a7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6510,6 +6510,12 @@
     <!-- Title for Default Apps settings [CHAR LIMIT=30] -->
     <string name="default_apps_title">Default Apps</string>
 
+    <!-- Title for Default Assist settings [CHAR LIMIT=30] -->
+    <string name="default_assist_title">Assist</string>
+
+    <!-- Summary for No Default Assist settings [CHAR LIMIT=45] -->
+    <string name="default_assist_none">No default Assist</string>
+
     <!-- Title for Default Browser settings [CHAR LIMIT=30] -->
     <string name="default_browser_title">Browser app</string>
 
@@ -6637,4 +6643,12 @@
     <!-- Settings item summary for active app [CHAR LIMIT=100] -->
     <string name="inactive_app_active_summary">Active. Touch to toggle.</string>
 
+    <!-- Title for the "context" preference to determine whether assist can access the data currently displayed on-screen [CHAR LIMIT=40] -->
+    <string name="assist_access_context_title">Use current context</string>
+
+    <!-- Summary for the "context" preference to determine whether assist can access the data currently displayed on-screen [CHAR LIMIT=NONE] -->
+    <string name="assist_access_context_summary">When you open the assist app, let it see what you\'ve been doing on your screen</string>
+
+    <!-- Footer text in the manage assist screen. [CHAR LIMIT=NONE] -->
+    <string name="assist_footer">Assist apps help you identify and act on useful information without having to ask. Some apps support both launcher and voice input services to give you integrated assistance.</string>
 </resources>
diff --git a/res/xml/default_apps.xml b/res/xml/default_apps.xml
index 7fc32fd..ab65ac8 100644
--- a/res/xml/default_apps.xml
+++ b/res/xml/default_apps.xml
@@ -19,6 +19,12 @@
         xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
         android:key="default_apps">
 
+    <Preference
+        android:key="default_assist"
+        android:fragment="com.android.settings.applications.ManageAssist"
+        android:title="@string/default_assist_title"
+        />
+
     <com.android.settings.applications.DefaultBrowserPreference
             android:key="default_browser"
             android:title="@string/default_browser_title"
diff --git a/res/xml/manage_assist.xml b/res/xml/manage_assist.xml
new file mode 100644
index 0000000..00e86ad
--- /dev/null
+++ b/res/xml/manage_assist.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<PreferenceScreen
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:key="manage_assist">
+
+    <SwitchPreference
+        android:key="context"
+        android:title="@string/assist_access_context_title"
+        android:summary="@string/assist_access_context_summary"
+        android:persistent="false" />
+</PreferenceScreen>
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 7ce581f..c256f5c 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -1272,8 +1272,7 @@
                             ((UserManager) getSystemService(Context.USER_SERVICE))
                                     .getUserCount() > 1;
                     if (!UserHandle.MU_ENABLED
-                            || (!UserManager.supportsMultipleUsers()
-                                    && !hasMultipleUsers)
+                            || !UserManager.supportsMultipleUsers()
                             || Utils.isMonkeyRunning()) {
                         removeTile = true;
                     }
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 16234ba..124f9da 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -237,6 +237,8 @@
             getActivity().getActionBar().setTitle(R.string.usage_access_title);
         } else if (className.equals(HighPowerApplicationsActivity.class.getName())) {
             mListType = LIST_TYPE_HIGH_POWER;
+            // Default to showing system.
+            mShowSystem = true;
         } else {
             mListType = LIST_TYPE_MAIN;
         }
diff --git a/src/com/android/settings/applications/ManageAssist.java b/src/com/android/settings/applications/ManageAssist.java
new file mode 100644
index 0000000..e222e1c
--- /dev/null
+++ b/src/com/android/settings/applications/ManageAssist.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.applications;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.text.method.LinkMovementMethod;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+/**
+ * Settings screen to manage everything about assist.
+ */
+public class ManageAssist extends SettingsPreferenceFragment
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final String KEY_CONTEXT = "context";
+
+    private SwitchPreference mContextPref;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        addPreferencesFromResource(R.xml.manage_assist);
+        mContextPref = (SwitchPreference) findPreference(KEY_CONTEXT);
+        mContextPref.setChecked(Settings.Secure.getInt(getContentResolver(),
+                Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0);
+        mContextPref.setOnPreferenceChangeListener(this);
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        TextView v = (TextView) LayoutInflater.from(view.getContext()).inflate(
+                R.layout.manage_assist_footer, null);
+        getListView().addFooterView(v);
+    }
+
+    @Override
+    protected int getMetricsCategory() {
+        return MetricsLogger.APPLICATIONS_MANAGE_ASSIST;
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mContextPref) {
+            Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSIST_STRUCTURE_ENABLED,
+                    (boolean) newValue ? 1 : 0);
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index cef0833..d61032b 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -200,7 +200,7 @@
         final Context context = getActivity();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         boolean hasMultipleUsers = mUserManager.getUserCount() > 1;
-        if ((!UserManager.supportsMultipleUsers() && !hasMultipleUsers)
+        if ((!UserManager.supportsMultipleUsers())
                 || Utils.isMonkeyRunning()) {
             mEnabled = false;
             return;
diff --git a/src/com/android/settings/vpn2/AppDialog.java b/src/com/android/settings/vpn2/AppDialog.java
index cd6a16c..c06de14 100644
--- a/src/com/android/settings/vpn2/AppDialog.java
+++ b/src/com/android/settings/vpn2/AppDialog.java
@@ -41,28 +41,25 @@
  */
 class AppDialog extends AlertDialog implements DialogInterface.OnClickListener {
     private final Listener mListener;
-    private final PackageInfo mPkgInfo;
+    private final PackageInfo mPackageInfo;
     private final String mLabel;
-    private final boolean mConnected;
 
-    AppDialog(Context context, Listener listener, PackageInfo pkgInfo, String label,
-            boolean connected) {
+    AppDialog(Context context, Listener listener, PackageInfo pkgInfo, String label) {
         super(context);
 
         mListener = listener;
-        mPkgInfo = pkgInfo;
+        mPackageInfo = pkgInfo;
         mLabel = label;
-        mConnected = connected;
     }
 
     public final PackageInfo getPackageInfo() {
-        return mPkgInfo;
+        return mPackageInfo;
     }
 
     @Override
     protected void onCreate(Bundle savedState) {
         setTitle(mLabel);
-        setMessage(getContext().getString(R.string.vpn_version, mPkgInfo.versionName));
+        setMessage(getContext().getString(R.string.vpn_version, mPackageInfo.versionName));
 
         createButtons();
         super.onCreate(savedState);
@@ -71,11 +68,9 @@
     protected void createButtons() {
         Context context = getContext();
 
-        if (mConnected) {
-            // Forget the network
-            setButton(DialogInterface.BUTTON_NEGATIVE,
-                    context.getString(R.string.vpn_forget), this);
-        }
+        // Forget the network
+        setButton(DialogInterface.BUTTON_NEGATIVE,
+                context.getString(R.string.vpn_forget), this);
 
         // Dismiss
         setButton(DialogInterface.BUTTON_POSITIVE,
diff --git a/src/com/android/settings/vpn2/AppDialogFragment.java b/src/com/android/settings/vpn2/AppDialogFragment.java
index 6ac4fb5..906f896 100644
--- a/src/com/android/settings/vpn2/AppDialogFragment.java
+++ b/src/com/android/settings/vpn2/AppDialogFragment.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.net.VpnConfig;
@@ -41,18 +42,20 @@
 
     private static final String ARG_MANAGING = "managing";
     private static final String ARG_LABEL = "label";
-    private static final String ARG_PACKAGE = "package";
     private static final String ARG_CONNECTED = "connected";
+    private static final String ARG_PACKAGE = "package";
+
+    private PackageInfo mPackageInfo;
 
     private final IConnectivityManager mService = IConnectivityManager.Stub.asInterface(
             ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
-    public static void show(VpnSettings parent, PackageInfo pkgInfo, String label, boolean managing,
-            boolean connected) {
+    public static void show(VpnSettings parent, PackageInfo packageInfo, String label,
+            boolean managing, boolean connected) {
         if (!parent.isAdded()) return;
 
         Bundle args = new Bundle();
-        args.putParcelable(ARG_PACKAGE, pkgInfo);
+        args.putParcelable(ARG_PACKAGE, packageInfo);
         args.putString(ARG_LABEL, label);
         args.putBoolean(ARG_MANAGING, managing);
         args.putBoolean(ARG_CONNECTED, connected);
@@ -66,13 +69,13 @@
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         Bundle args = getArguments();
-        PackageInfo pkgInfo = (PackageInfo) args.getParcelable(ARG_PACKAGE);
-        String label = args.getString(ARG_LABEL);
+        final String label = args.getString(ARG_LABEL);
         boolean managing = args.getBoolean(ARG_MANAGING);
         boolean connected = args.getBoolean(ARG_CONNECTED);
+        mPackageInfo = (PackageInfo) args.getParcelable(ARG_PACKAGE);
 
         if (managing) {
-            return new AppDialog(getActivity(), this, pkgInfo, label, connected);
+            return new AppDialog(getActivity(), this, mPackageInfo, label);
         } else {
             // Build an AlertDialog with an option to disconnect.
             AlertDialog.Builder dlog = new AlertDialog.Builder(getActivity())
@@ -94,12 +97,6 @@
     }
 
     @Override
-    public void dismiss() {
-        ((VpnSettings) getTargetFragment()).update();
-        super.dismiss();
-    }
-
-    @Override
     public void onCancel(DialogInterface dialog) {
         dismiss();
         super.onCancel(dialog);
@@ -107,25 +104,29 @@
 
     @Override
     public void onForget(final DialogInterface dialog) {
-        PackageInfo pkgInfo = (PackageInfo) getArguments().getParcelable(ARG_PACKAGE);
-        final String pkg = pkgInfo.packageName;
+        final int userId = UserHandle.getUserId(mPackageInfo.applicationInfo.uid);
         try {
-            VpnConfig vpnConfig = mService.getVpnConfig();
-            if (vpnConfig != null && pkg.equals(vpnConfig.user) && !vpnConfig.legacy) {
-                mService.setVpnPackageAuthorization(false);
-                onDisconnect(dialog);
-            }
+            mService.setVpnPackageAuthorization(mPackageInfo.packageName, userId, false);
+            onDisconnect(dialog);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to forget authorization for " + pkg, e);
+            Log.e(TAG, "Failed to forget authorization of " + mPackageInfo.packageName +
+                    " for user " + userId, e);
         }
     }
 
     private void onDisconnect(final DialogInterface dialog) {
-        PackageInfo pkgInfo = (PackageInfo) getArguments().getParcelable(ARG_PACKAGE);
+        final int userId = UserHandle.getUserId(mPackageInfo.applicationInfo.uid);
         try {
-            mService.prepareVpn(pkgInfo.packageName, VpnConfig.LEGACY_VPN);
+            final VpnConfig vpnConfig = mService.getVpnConfig(userId);
+            if (vpnConfig == null || vpnConfig.legacy) {
+                return;
+            }
+            if (mPackageInfo.packageName.equals(vpnConfig.user)) {
+                mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId);
+            }
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to disconnect package " + pkgInfo.packageName, e);
+            Log.e(TAG, "Failed to disconnect package " + mPackageInfo.packageName +
+                    " for user " + userId, e);
         }
     }
 }
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index 42e1614..26b7982 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.util.Log;
@@ -128,12 +129,6 @@
     }
 
     @Override
-    public void dismiss() {
-        ((VpnSettings) getTargetFragment()).update();
-        super.dismiss();
-    }
-
-    @Override
     public void onCancel(DialogInterface dialog) {
         dismiss();
         super.onCancel(dialog);
@@ -151,7 +146,8 @@
         try {
             LegacyVpnInfo connected = mService.getLegacyVpnInfo();
             if (connected != null && profile.key.equals(connected.key)) {
-                mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+                mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN,
+                        UserHandle.myUserId());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to disconnect", e);
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index e60a262..a82585d 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -71,6 +71,9 @@
         Handler.Callback, Preference.OnPreferenceClickListener {
     private static final String LOG_TAG = "VpnSettings";
 
+    private static final int RESCAN_MESSAGE = 0;
+    private static final int RESCAN_INTERVAL_MS = 1000;
+
     private static final String EXTRA_PICK_LOCKDOWN = "android.net.vpn.PICK_LOCKDOWN";
     private static final NetworkRequest VPN_REQUEST = new NetworkRequest.Builder()
             .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
@@ -90,7 +93,6 @@
 
     private Handler mUpdater;
     private LegacyVpnInfo mConnectedLegacyVpn;
-    private HashSet<String> mConnectedVpns = new HashSet<>();
 
     private boolean mUnavailable;
 
@@ -111,7 +113,6 @@
         }
 
         mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-        mConnectivityManager.registerNetworkCallback(VPN_REQUEST, mNetworkCallback);
 
         setHasOptionsMenu(true);
         addPreferencesFromResource(R.xml.vpn_settings2);
@@ -179,10 +180,32 @@
             LockdownConfigFragment.show(this);
         }
 
-        update();
+        // Start monitoring
+        mConnectivityManager.registerNetworkCallback(VPN_REQUEST, mNetworkCallback);
+
+        // Trigger a refresh
+        if (mUpdater == null) {
+            mUpdater = new Handler(this);
+        }
+        mUpdater.sendEmptyMessage(RESCAN_MESSAGE);
     }
 
-    public void update() {
+    @Override
+    public void onPause() {
+        // Pause monitoring
+        mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+
+        if (mUpdater != null) {
+            mUpdater.removeCallbacksAndMessages(null);
+        }
+
+        super.onPause();
+    }
+
+    @Override
+    public boolean handleMessage(Message message) {
+        mUpdater.removeMessages(RESCAN_MESSAGE);
+
         // Pref group within which to list VPNs
         PreferenceGroup vpnGroup = getPreferenceScreen();
         vpnGroup.removeAll();
@@ -200,18 +223,43 @@
 
         // 3rd-party VPN apps can change elsewhere. Reload them every time.
         for (AppOpsManager.PackageOps pkg : getVpnApps()) {
+            String key = getVpnIdentifier(UserHandle.getUserId(pkg.getUid()), pkg.getPackageName());
             final AppPreference pref = new AppPreference(getActivity(), mManageListener,
                     pkg.getPackageName(), pkg.getUid());
             pref.setOnPreferenceClickListener(this);
-            mAppPreferences.put(pkg.getPackageName(), pref);
+            mAppPreferences.put(key, pref);
             vpnGroup.addPreference(pref);
         }
 
-        // Start monitoring.
-        if (mUpdater == null) {
-            mUpdater = new Handler(this);
+        // Mark out connections with a subtitle
+        try {
+            // Legacy VPNs
+            LegacyVpnInfo info = mConnectivityService.getLegacyVpnInfo();
+            if (info != null) {
+                ConfigPreference preference = mConfigPreferences.get(info.key);
+                if (preference != null) {
+                    preference.setState(info.state);
+                    mConnectedLegacyVpn = info;
+                }
+            }
+
+            // Third-party VPNs
+            for (UserHandle profile : mUserManager.getUserProfiles()) {
+                VpnConfig cfg = mConnectivityService.getVpnConfig(profile.getIdentifier());
+                if (cfg != null) {
+                    final String key = getVpnIdentifier(profile.getIdentifier(), cfg.user);
+                    final AppPreference preference = mAppPreferences.get(key);
+                    if (preference != null) {
+                        preference.setState(AppPreference.STATE_CONNECTED);
+                    }
+                }
+            }
+        } catch (RemoteException e) {
+            // ignore
         }
-        mUpdater.sendEmptyMessage(0);
+
+        mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS);
+        return true;
     }
 
     @Override
@@ -275,68 +323,22 @@
         }
     };
 
-    @Override
-    public boolean handleMessage(Message message) {
-        mUpdater.removeMessages(0);
-
-        if (isResumed()) {
-            try {
-                // Legacy VPNs
-                LegacyVpnInfo info = mConnectivityService.getLegacyVpnInfo();
-                if (mConnectedLegacyVpn != null) {
-                    ConfigPreference preference = mConfigPreferences.get(mConnectedLegacyVpn.key);
-                    if (preference != null) {
-                        preference.setState(-1);
-                    }
-                    mConnectedLegacyVpn = null;
-                }
-                if (info != null) {
-                    ConfigPreference preference = mConfigPreferences.get(info.key);
-                    if (preference != null) {
-                        preference.setState(info.state);
-                        mConnectedLegacyVpn = info;
-                    }
-                }
-
-                // VPN apps
-                for (String key : mConnectedVpns) {
-                    AppPreference preference = mAppPreferences.get(key);
-                    if (preference != null) {
-                        preference.setState(AppPreference.STATE_DISCONNECTED);
-                    }
-                }
-                mConnectedVpns.clear();
-                // TODO: also query VPN services in user profiles STOPSHIP
-                VpnConfig cfg = mConnectivityService.getVpnConfig();
-                if (cfg != null) {
-                    mConnectedVpns.add(cfg.user);
-                }
-                for (String key : mConnectedVpns) {
-                    AppPreference preference = mAppPreferences.get(key);
-                    if (preference != null) {
-                        preference.setState(AppPreference.STATE_CONNECTED);
-                    }
-                }
-            } catch (RemoteException e) {
-                // ignore
-            }
-            mUpdater.sendEmptyMessageDelayed(0, 1000);
-        }
-        return true;
+    private static String getVpnIdentifier(int userId, String packageName) {
+        return Integer.toString(userId)+ "_" + packageName;
     }
 
     private NetworkCallback mNetworkCallback = new NetworkCallback() {
         @Override
         public void onAvailable(Network network) {
             if (mUpdater != null) {
-                mUpdater.sendEmptyMessage(0);
+                mUpdater.sendEmptyMessage(RESCAN_MESSAGE);
             }
         }
 
         @Override
         public void onLost(Network network) {
             if (mUpdater != null) {
-                mUpdater.sendEmptyMessage(0);
+                mUpdater.sendEmptyMessage(RESCAN_MESSAGE);
             }
         }
     };
diff --git a/src/com/android/settings/wifi/AccessPointPreference.java b/src/com/android/settings/wifi/AccessPointPreference.java
index 511d88d..55d575e 100644
--- a/src/com/android/settings/wifi/AccessPointPreference.java
+++ b/src/com/android/settings/wifi/AccessPointPreference.java
@@ -18,9 +18,12 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
+import android.net.wifi.WifiConfiguration;
+import android.os.UserHandle;
 import android.preference.Preference;
 import android.view.View;
 import android.widget.TextView;
+
 import com.android.settings.R;
 import com.android.settingslib.wifi.AccessPoint;
 
@@ -33,6 +36,7 @@
 
     private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
 
+    private TextView mTitleView;
     private TextView mSummaryView;
     private boolean showSummary = true;
     private boolean mForSavedNetworks = false;
@@ -56,9 +60,12 @@
         super.onBindView(view);
         updateIcon(mAccessPoint.getLevel(), getContext());
 
+        mTitleView = (TextView) view.findViewById(com.android.internal.R.id.title);
+
         mSummaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
         mSummaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
 
+        updateBadge(getContext());
         notifyChanged();
     }
 
@@ -94,6 +101,27 @@
         }
     }
 
+    protected void updateBadge(Context context) {
+        if (mTitleView != null) {
+            WifiConfiguration config = mAccessPoint.getConfig();
+            if (config == null) {
+                return;
+            }
+            // Fetch badge (may be null)
+            UserHandle creatorUser = new UserHandle(UserHandle.getUserId(config.creatorUid));
+            Drawable badge =
+                    context.getPackageManager().getUserBadgeForDensity(creatorUser, 0 /* dpi */);
+
+            // Distance from the end of the title at which this AP's user badge should sit.
+            final int badgePadding = context.getResources()
+                    .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
+
+            // Attach to the end of the title view
+            mTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, badge, null);
+            mTitleView.setCompoundDrawablePadding(badgePadding);
+        }
+    }
+
     /**
      * Shows or Hides the Summary of an AccessPoint.
      *
@@ -117,6 +145,7 @@
 
         final Context context = getContext();
         updateIcon(mAccessPoint.getLevel(), context);
+        updateBadge(context);
 
         // Force new summary
         setSummary(null);
diff --git a/tests/src/com/android/settings/vpn2/VpnTests.java b/tests/src/com/android/settings/vpn2/VpnTests.java
index 8300534..26cfc9b 100644
--- a/tests/src/com/android/settings/vpn2/VpnTests.java
+++ b/tests/src/com/android/settings/vpn2/VpnTests.java
@@ -22,6 +22,7 @@
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.security.NetworkSecurityPolicy;
@@ -214,7 +215,7 @@
      */
     private void disconnect() throws Exception {
         try {
-            mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+            mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, UserHandle.myUserId());
         } catch (RemoteException e) {
             Log.e(TAG, String.format("disconnect VPN exception: %s", e.toString()));
         }