Merge "Address TODOs in WifiNoInternetDialog." into mnc-dev
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 feb10a7..c00d904 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2451,6 +2451,12 @@
     <!-- Title of wizard button offering to cancel move [CHAR LIMIT=32] -->
     <string name="storage_wizard_move_progress_cancel">Cancel move</string>
 
+    <!-- Title of wizard step prompting user to start data migration [CHAR LIMIT=32] -->
+    <string name="storage_wizard_slow_body">This <xliff:g id="name" example="SD card">^1</xliff:g> appears to be slow.
+\n\nYou can continue, but apps moved to this location may stutter and data transfers may take a long time.
+\n\nConsider using a faster <xliff:g id="name" example="SD card">^1</xliff:g> for better performance.
+</string>
+
     <!-- Phone info screen, section titles: -->
     <string name="battery_status_title">Battery status</string>
     <!-- Phone info screen, section titles: -->
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
index 1338ac7..6a2ff5e 100644
--- a/src/com/android/settings/ChooseLockPassword.java
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -21,6 +21,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.PasswordEntryKeyboardHelper;
 import com.android.internal.widget.PasswordEntryKeyboardView;
+import com.android.internal.widget.TextViewInputDisabler;
 import com.android.settings.notification.RedactionInterstitial;
 
 import android.app.Activity;
@@ -127,6 +128,7 @@
         private boolean mHasChallenge;
         private long mChallenge;
         private TextView mPasswordEntry;
+        private TextViewInputDisabler mPasswordEntryInputDisabler;
         private int mPasswordMinLength = LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
         private int mPasswordMaxLength = 16;
         private int mPasswordMinLetters = 0;
@@ -255,6 +257,7 @@
             mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
             mPasswordEntry.setOnEditorActionListener(this);
             mPasswordEntry.addTextChangedListener(this);
+            mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
 
             final Activity activity = getActivity();
             mKeyboardHelper = new PasswordEntryKeyboardHelper(activity,
@@ -315,7 +318,7 @@
         public void onResume() {
             super.onResume();
             updateStage(mUiStage);
-            mPasswordEntry.setEnabled(true);
+            mPasswordEntryInputDisabler.setInputEnabled(true);
             mKeyboardView.requestFocus();
         }
 
@@ -517,7 +520,7 @@
         }
 
         private void startVerifyPassword(final String pin, final boolean wasSecureBefore) {
-            mPasswordEntry.setEnabled(false);
+            mPasswordEntryInputDisabler.setInputEnabled(false);
             setNextEnabled(false);
             if (mPendingLockCheck != null) {
                 mPendingLockCheck.cancel(false);
@@ -531,7 +534,7 @@
                     new LockPatternChecker.OnVerifyCallback() {
                         @Override
                         public void onVerified(byte[] token) {
-                            mPasswordEntry.setEnabled(true);
+                            mPasswordEntryInputDisabler.setInputEnabled(true);
                             setNextEnabled(true);
                             mPendingLockCheck = null;
 
@@ -598,7 +601,7 @@
         private void updateUi() {
             String password = mPasswordEntry.getText().toString();
             final int length = password.length();
-            if (mUiStage == Stage.Introduction && length > 0) {
+            if (mUiStage == Stage.Introduction) {
                 if (length < mPasswordMinLength) {
                     String msg = getString(mIsAlphaMode ? R.string.lockpassword_password_too_short
                             : R.string.lockpassword_pin_too_short, mPasswordMinLength);
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 388fde7..c1d8adb 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -22,6 +22,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.TextViewInputDisabler;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Intent;
@@ -66,6 +67,7 @@
                 = "confirm_lock_password_fragment.key_num_wrong_confirm_attempts";
         private static final long ERROR_MESSAGE_TIMEOUT = 3000;
         private TextView mPasswordEntry;
+        private TextViewInputDisabler mPasswordEntryInputDisabler;
         private LockPatternUtils mLockPatternUtils;
         private AsyncTask<?, ?, ?> mPendingLockCheck;
         private TextView mHeaderTextView;
@@ -100,6 +102,7 @@
 
             mPasswordEntry = (TextView) view.findViewById(R.id.password_entry);
             mPasswordEntry.setOnEditorActionListener(this);
+            mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
 
             mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
             mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
@@ -169,7 +172,7 @@
             if (deadline != 0) {
                 handleAttemptLockout(deadline);
             } else {
-                mPasswordEntry.setEnabled(true);
+                mPasswordEntryInputDisabler.setInputEnabled(true);
             }
         }
 
@@ -187,7 +190,7 @@
         }
 
         private void handleNext() {
-            mPasswordEntry.setEnabled(false);
+            mPasswordEntryInputDisabler.setInputEnabled(false);
             if (mPendingLockCheck != null) {
                 mPendingLockCheck.cancel(false);
             }
@@ -259,7 +262,7 @@
         }
 
         private void onPasswordChecked(boolean matched, Intent intent) {
-            mPasswordEntry.setEnabled(true);
+            mPasswordEntryInputDisabler.setInputEnabled(true);
             if (matched) {
                 getActivity().setResult(RESULT_OK, intent);
                 getActivity().finish();
@@ -276,7 +279,7 @@
 
         private void handleAttemptLockout(long elapsedRealtimeDeadline) {
             long elapsedRealtime = SystemClock.elapsedRealtime();
-            mPasswordEntry.setEnabled(false);
+            mPasswordEntryInputDisabler.setInputEnabled(false);
             mCountdownTimer = new CountDownTimer(
                     elapsedRealtimeDeadline - elapsedRealtime,
                     LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
@@ -291,7 +294,7 @@
 
                 @Override
                 public void onFinish() {
-                    mPasswordEntry.setEnabled(true);
+                    mPasswordEntryInputDisabler.setInputEnabled(true);
                     mErrorTextView.setText("");
                     mNumWrongConfirmAttempts = 0;
                 }
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/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index e2e6dbe..f1f4510 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -18,7 +18,11 @@
 
 import static com.android.settings.deviceinfo.StorageSettings.TAG;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -33,6 +37,8 @@
 import com.android.settings.R;
 
 public class StorageWizardFormatProgress extends StorageWizardBase {
+    private static final String TAG_SLOW_WARNING = "slow_warning";
+
     private boolean mFormatPrivate;
 
     @Override
@@ -56,6 +62,9 @@
     }
 
     public class PartitionTask extends AsyncTask<Void, Integer, Exception> {
+        private volatile long mInternalBench;
+        private volatile long mPrivateBench;
+
         @Override
         protected Exception doInBackground(Void... params) {
             try {
@@ -63,15 +72,12 @@
                     mStorage.partitionPrivate(mDisk.getId());
                     publishProgress(40);
 
-                    final long internalBench = mStorage.benchmark(null);
+                    mInternalBench = mStorage.benchmark(null);
                     publishProgress(60);
 
                     final VolumeInfo privateVol = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
-                    final long privateBench = mStorage.benchmark(privateVol.id);
+                    mPrivateBench = mStorage.benchmark(privateVol.id);
 
-                    // TODO: plumb through to user when below threshold
-                    final float pct = (float) internalBench / (float) privateBench;
-                    Log.d(TAG, "New volume is " + pct + "x the speed of internal");
                 } else {
                     mStorage.partitionPublic(mDisk.getId());
                 }
@@ -89,40 +95,89 @@
         @Override
         protected void onPostExecute(Exception e) {
             final Context context = StorageWizardFormatProgress.this;
-            if (e == null) {
-                final String forgetUuid = getIntent().getStringExtra(
-                        StorageWizardFormatConfirm.EXTRA_FORGET_UUID);
-                if (!TextUtils.isEmpty(forgetUuid)) {
-                    mStorage.forgetVolume(forgetUuid);
-                }
-
-                final boolean offerMigrate;
-                if (mFormatPrivate) {
-                    // Offer to migrate only if storage is currently internal
-                    final VolumeInfo privateVol = getPackageManager()
-                            .getPrimaryStorageCurrentVolume();
-                    offerMigrate = (privateVol != null
-                            && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.getId()));
-                } else {
-                    offerMigrate = false;
-                }
-
-                if (offerMigrate) {
-                    final Intent intent = new Intent(context, StorageWizardMigrate.class);
-                    intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
-                    startActivity(intent);
-                } else {
-                    final Intent intent = new Intent(context, StorageWizardReady.class);
-                    intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
-                    startActivity(intent);
-                }
-                finishAffinity();
-
-            } else {
+            if (e != null) {
                 Log.e(TAG, "Failed to partition", e);
                 Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
                 finishAffinity();
+                return;
+            }
+
+            final float pct = (float) mInternalBench / (float) mPrivateBench;
+            Log.d(TAG, "New volume is " + pct + "x the speed of internal");
+
+            // TODO: refine this warning threshold
+            if (mPrivateBench > 2000000000) {
+                final SlowWarningFragment dialog = new SlowWarningFragment();
+                dialog.show(getFragmentManager(), TAG_SLOW_WARNING);
+            } else {
+                onFormatFinished();
             }
         }
     }
+
+    public class SlowWarningFragment extends DialogFragment {
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Context context = getActivity();
+
+            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+
+            final String descrip = mDisk.getDescription();
+            final String genericDescip = getGenericDescription(mDisk);
+            builder.setMessage(TextUtils.expandTemplate(getText(R.string.storage_wizard_slow_body),
+                    descrip, genericDescip));
+
+            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    final StorageWizardFormatProgress target =
+                            (StorageWizardFormatProgress) getActivity();
+                    target.onFormatFinished();
+                }
+            });
+
+            return builder.create();
+        }
+    }
+
+    private String getGenericDescription(DiskInfo disk) {
+        // TODO: move this directly to DiskInfo
+        if (disk.isSd()) {
+            return getString(com.android.internal.R.string.storage_sd_card);
+        } else if (disk.isUsb()) {
+            return getString(com.android.internal.R.string.storage_usb_drive);
+        } else {
+            return null;
+        }
+    }
+
+    private void onFormatFinished() {
+        final String forgetUuid = getIntent().getStringExtra(
+                StorageWizardFormatConfirm.EXTRA_FORGET_UUID);
+        if (!TextUtils.isEmpty(forgetUuid)) {
+            mStorage.forgetVolume(forgetUuid);
+        }
+
+        final boolean offerMigrate;
+        if (mFormatPrivate) {
+            // Offer to migrate only if storage is currently internal
+            final VolumeInfo privateVol = getPackageManager()
+                    .getPrimaryStorageCurrentVolume();
+            offerMigrate = (privateVol != null
+                    && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.getId()));
+        } else {
+            offerMigrate = false;
+        }
+
+        if (offerMigrate) {
+            final Intent intent = new Intent(this, StorageWizardMigrate.class);
+            intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+            startActivity(intent);
+        } else {
+            final Intent intent = new Intent(this, StorageWizardReady.class);
+            intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+            startActivity(intent);
+        }
+        finishAffinity();
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java b/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java
index 76b2fd1..e0369d6 100644
--- a/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java
+++ b/src/com/android/settings/deviceinfo/UsbModeChooserActivity.java
@@ -18,12 +18,14 @@
 
 import android.annotation.Nullable;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.util.Log;
+
 import com.android.settings.R;
 
 /**
@@ -46,7 +48,9 @@
                 new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        setCurrentFunction(which);
+                        if (!ActivityManager.isUserAMonkey()) {
+                            setCurrentFunction(which);
+                        }
                         dialog.dismiss();
                         UsbModeChooserActivity.this.finish();
                     }
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 4d28d4a..8aba203 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -208,7 +208,7 @@
         sResMap.put(UserSettings.class.getName(),
                 new SearchIndexableResource(
                         Ranking.getRankForClassName(UserSettings.class.getName()),
-                        R.xml.user_settings,
+                        NO_DATA_RES_ID,
                         UserSettings.class.getName(),
                         R.drawable.ic_settings_multiuser));
 
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index cef0833..d5244d7 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -22,7 +22,6 @@
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.Fragment;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -66,6 +65,9 @@
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
 import com.android.settings.drawable.CircleFramedDrawable;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -83,7 +85,7 @@
 public class UserSettings extends SettingsPreferenceFragment
         implements OnPreferenceClickListener, OnClickListener, DialogInterface.OnDismissListener,
         Preference.OnPreferenceChangeListener,
-        EditUserInfoController.OnContentChangedCallback {
+        EditUserInfoController.OnContentChangedCallback, Indexable {
 
     private static final String TAG = "UserSettings";
 
@@ -131,15 +133,11 @@
     private int mRemovingUserId = -1;
     private int mAddedUserId = 0;
     private boolean mAddingUser;
-    private boolean mEnabled = true;
-    private boolean mCanAddUser = true;
-    private boolean mCanAddRestrictedProfile = true;
+    private UserCapabilities mUserCaps;
 
     private final Object mUserLock = new Object();
     private UserManager mUserManager;
     private SparseArray<Bitmap> mUserIcons = new SparseArray<Bitmap>();
-    private boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
-    private boolean mIsGuest;
 
     private EditUserInfoController mEditUserInfoController =
             new EditUserInfoController();
@@ -198,16 +196,13 @@
             mEditUserInfoController.onRestoreInstanceState(icicle);
         }
         final Context context = getActivity();
+        mUserCaps = UserCapabilities.create(context);
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        boolean hasMultipleUsers = mUserManager.getUserCount() > 1;
-        if ((!UserManager.supportsMultipleUsers() && !hasMultipleUsers)
-                || Utils.isMonkeyRunning()) {
-            mEnabled = false;
+        if (!mUserCaps.mEnabled) {
             return;
         }
 
         final int myUserId = UserHandle.myUserId();
-        mIsGuest = mUserManager.getUserInfo(myUserId).isGuest();
 
         addPreferencesFromResource(R.xml.user_settings);
         mUserListCategory = (PreferenceGroup) findPreference(KEY_USER_LIST);
@@ -216,25 +211,15 @@
                 null /* delete icon handler */);
         mMePreference.setKey(KEY_USER_ME);
         mMePreference.setOnPreferenceClickListener(this);
-        if (mIsOwner) {
+        if (mUserCaps.mIsOwner) {
             mMePreference.setSummary(R.string.user_owner);
         }
         mAddUser = findPreference(KEY_ADD_USER);
-        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        // No restricted profiles for tablets with a device owner, or phones.
-        if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) {
-            mCanAddRestrictedProfile = false;
-        }
         // Determine if add user/profile button should be visible
-        if (!mIsOwner || UserManager.getMaxSupportedUsers() < 2
-                || !UserManager.supportsMultipleUsers()
-                || mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
-            mCanAddUser = false;
-        } else {
+        if (mUserCaps.mCanAddUser) {
             mAddUser.setOnPreferenceClickListener(this);
             // change label to only mention user, if restricted profiles are not supported
-            if (!mCanAddRestrictedProfile) {
+            if (!mUserCaps.mCanAddRestrictedProfile) {
                 mAddUser.setTitle(R.string.user_add_user_menu);
             }
         }
@@ -250,7 +235,7 @@
     public void onResume() {
         super.onResume();
 
-        if (!mEnabled) return;
+        if (!mUserCaps.mEnabled) return;
 
         loadProfile();
         updateUserList();
@@ -260,7 +245,7 @@
     public void onDestroy() {
         super.onDestroy();
 
-        if (!mEnabled) return;
+        if (!mUserCaps.mEnabled) return;
 
         getActivity().unregisterReceiver(mUserChangeReceiver);
     }
@@ -283,13 +268,13 @@
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         int pos = 0;
         UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
-        if (!mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)) {
+        if (!mUserCaps.mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER)) {
             String nickname = mUserManager.getUserName();
             MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, pos++,
                     getResources().getString(R.string.user_remove_user_menu, nickname));
             removeThisUser.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         }
-        if (mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
+        if (mUserCaps.mIsOwner && !um.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
             MenuItem allowAddOnLockscreen = menu.add(0, MENU_ADD_ON_LOCKSCREEN, pos++,
                     R.string.user_add_on_lockscreen_menu);
             allowAddOnLockscreen.setCheckable(true);
@@ -320,7 +305,7 @@
      * Loads profile information for the current user.
      */
     private void loadProfile() {
-        if (mIsGuest) {
+        if (mUserCaps.mIsGuest) {
             // No need to load profile information
             mMePreference.setIcon(getEncircledDefaultIcon());
             mMePreference.setTitle(R.string.user_exit_guest_title);
@@ -451,7 +436,7 @@
             return;
         }
         UserInfo info = mUserManager.getUserInfo(userId);
-        if (info.isRestricted() && mIsOwner) {
+        if (info.isRestricted() && mUserCaps.mIsOwner) {
             Bundle extras = new Bundle();
             extras.putInt(RestrictedProfileSettings.EXTRA_USER_ID, userId);
             extras.putBoolean(RestrictedProfileSettings.EXTRA_NEW_USER, newUser);
@@ -462,7 +447,7 @@
         } else if (info.id == UserHandle.myUserId()) {
             // Jump to owner info panel
             OwnerInfoSettings.show(this);
-        } else if (mIsOwner) {
+        } else if (mUserCaps.mIsOwner) {
             Bundle extras = new Bundle();
             extras.putInt(UserDetailsSettings.EXTRA_USER_ID, userId);
             ((SettingsActivity) getActivity()).startPreferencePanel(
@@ -624,7 +609,7 @@
             }
             case DIALOG_USER_PROFILE_EDITOR: {
                 Dialog dlg = mEditUserInfoController.createDialog(
-                        (Fragment) this,
+                        this,
                         mMePreference.getIcon(),
                         mMePreference.getTitle(),
                         R.string.profile_info_settings_title,
@@ -668,7 +653,7 @@
             //updateUserList();
             new Thread() {
                 public void run() {
-                    UserInfo user = null;
+                    UserInfo user;
                     // Could take a few seconds
                     if (userType == USER_TYPE_USER) {
                         user = createTrustedUser();
@@ -704,7 +689,7 @@
      */
     private void exitGuest() {
         // Just to be safe
-        if (!mIsGuest) {
+        if (!mUserCaps.mIsGuest) {
             return;
         }
         removeThisUser();
@@ -740,8 +725,9 @@
                 //   Secondary user: Delete
                 //   Guest: Nothing
                 //   Restricted Profile: Settings
-                final boolean showSettings = mIsOwner && (voiceCapable || user.isRestricted());
-                final boolean showDelete = mIsOwner
+                final boolean showSettings = mUserCaps.mIsOwner
+                        && (voiceCapable || user.isRestricted());
+                final boolean showDelete = mUserCaps.mIsOwner
                         && (!voiceCapable && !user.isRestricted() && !user.isGuest());
                 pref = new UserPreference(context, null, user.id,
                         showSettings ? this : null,
@@ -791,7 +777,7 @@
             // Add a virtual Guest user for guest defaults
             UserPreference pref = new UserPreference(getActivity(), null,
                     UserPreference.USERID_GUEST_DEFAULTS,
-                    mIsOwner && voiceCapable? this : null /* settings icon handler */,
+                    mUserCaps.mIsOwner && voiceCapable? this : null /* settings icon handler */,
                     null /* delete icon handler */);
             pref.setTitle(R.string.user_guest);
             pref.setIcon(getEncircledDefaultIcon());
@@ -816,7 +802,7 @@
         // "User & Profiles", otherwise the category is skipped and elements are added directly
         // to preferenceScreen
         PreferenceGroup groupToAddUsers;
-        if (mCanAddRestrictedProfile) {
+        if (mUserCaps.mCanAddRestrictedProfile) {
             mUserListCategory.removeAll();
             mUserListCategory.setOrder(Preference.DEFAULT_ORDER);
             preferenceScreen.addPreference(mUserListCategory);
@@ -830,7 +816,7 @@
         }
 
         // Append Add user to the end of the list
-        if (mCanAddUser) {
+        if (mUserCaps.mCanAddUser) {
             boolean moreUsers = mUserManager.canAddMoreUsers();
             mAddUser.setEnabled(moreUsers);
             mAddUser.setOrder(Preference.DEFAULT_ORDER);
@@ -839,7 +825,7 @@
     }
 
     private boolean shouldShowGuestUserPreference(List<UserInfo> users) {
-        boolean showGuestPreference = !mIsGuest;
+        boolean showGuestPreference = !mUserCaps.mIsGuest;
         // If user has DISALLOW_ADD_USER don't allow creating a guest either.
         if (showGuestPreference && mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
             showGuestPreference = false;
@@ -856,7 +842,6 @@
 
 
     private void loadIconsAsync(List<Integer> missingIcons) {
-        final Resources resources = getResources();
         new AsyncTask<List<Integer>, Void, Void>() {
             @Override
             protected void onPostExecute(Void result) {
@@ -911,7 +896,7 @@
     @Override
     public boolean onPreferenceClick(Preference pref) {
         if (pref == mMePreference) {
-            if (mIsGuest) {
+            if (mUserCaps.mIsGuest) {
                 showDialog(DIALOG_CONFIRM_EXIT_GUEST);
                 return true;
             }
@@ -938,7 +923,7 @@
         } else if (pref == mAddUser) {
             // If we allow both types, show a picker, otherwise directly go to
             // flow for full user.
-            if (mCanAddRestrictedProfile) {
+            if (mUserCaps.mCanAddRestrictedProfile) {
                 showDialog(DIALOG_CHOOSE_USER_TYPE);
             } else {
                 onAddUserClicked(USER_TYPE_USER);
@@ -958,7 +943,7 @@
         // No guest user. Create one, if there's no restriction.
         // If it is not the primary user, then adding users from lockscreen must be enabled
         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)
-                || (!mIsOwner && Settings.Global.getInt(getContentResolver(),
+                || (!mUserCaps.mIsOwner && Settings.Global.getInt(getContentResolver(),
                         Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 1)) {
             Log.i(TAG, "Blocking guest creation because it is restricted");
             return;
@@ -1030,4 +1015,76 @@
     public void onLabelChanged(CharSequence label) {
         mMePreference.setTitle(label);
     }
+
+    private static class UserCapabilities {
+        boolean mEnabled = true;
+        boolean mCanAddUser = true;
+        boolean mCanAddRestrictedProfile = true;
+        boolean mIsOwner = UserHandle.myUserId() == UserHandle.USER_OWNER;
+        boolean mIsGuest;
+
+        public static UserCapabilities create(Context context) {
+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+            UserCapabilities caps = new UserCapabilities();
+            if (!UserManager.supportsMultipleUsers() || Utils.isMonkeyRunning()) {
+                caps.mEnabled = false;
+                return caps;
+            }
+
+            if (!caps.mIsOwner || UserManager.getMaxSupportedUsers() < 2
+                    || !UserManager.supportsMultipleUsers()
+                    || userManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER)) {
+                caps.mCanAddUser = false;
+            }
+            DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+                    Context.DEVICE_POLICY_SERVICE);
+            // No restricted profiles for tablets with a device owner, or phones.
+            if (dpm.getDeviceOwner() != null || Utils.isVoiceCapable(context)) {
+                caps.mCanAddRestrictedProfile = false;
+            }
+            final int myUserId = UserHandle.myUserId();
+            caps.mIsGuest = userManager.getUserInfo(myUserId).isGuest();
+            return caps;
+        }
+
+        @Override
+        public String toString() {
+            return "UserCapabilities{" +
+                    "mEnabled=" + mEnabled +
+                    ", mCanAddUser=" + mCanAddUser +
+                    ", mCanAddRestrictedProfile=" + mCanAddRestrictedProfile +
+                    ", mIsOwner=" + mIsOwner +
+                    ", mIsGuest=" + mIsGuest +
+                    '}';
+        }
+    }
+
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+                        boolean enabled) {
+                    final List<SearchIndexableRaw> result = new ArrayList<>();
+                    final UserCapabilities userCaps = UserCapabilities.create(context);
+                    if (!userCaps.mEnabled) {
+                        return result;
+                    }
+                    final Resources res = context.getResources();
+                    SearchIndexableRaw data = new SearchIndexableRaw(context);
+                    data.title = res.getString(R.string.user_settings_title);
+                    data.screenTitle = res.getString(R.string.user_settings_title);
+                    result.add(data);
+
+                    if (userCaps.mCanAddUser) {
+                        data = new SearchIndexableRaw(context);
+                        data.title = res.getString(userCaps.mCanAddRestrictedProfile ?
+                                R.string.user_add_user_or_profile_menu
+                                : R.string.user_add_user_menu);
+                        data.screenTitle = res.getString(R.string.user_settings_title);
+                        result.add(data);
+                    }
+                    return result;
+                }
+            };
+
 }
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);