blob: cedc3c7eef2ff0d266ef4cbf3c4ef866917d3631 [file] [log] [blame]
Adrian Roos00a0b1f2014-07-16 16:44:49 +02001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.systemui.statusbar.policy;
18
Adrian Roos00a0b1f2014-07-16 16:44:49 +020019import android.app.ActivityManager;
20import android.app.ActivityManagerNative;
Adrian Roos50052442014-07-17 23:35:18 +020021import android.app.Dialog;
Fyodor Kupolovf4d6ad22015-04-13 11:52:18 -070022import android.app.Notification;
23import android.app.NotificationManager;
24import android.app.PendingIntent;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020025import android.content.BroadcastReceiver;
26import android.content.Context;
Adrian Roos50052442014-07-17 23:35:18 +020027import android.content.DialogInterface;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020028import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.pm.UserInfo;
Jason Monk2daf62c2014-07-31 14:35:06 -040031import android.database.ContentObserver;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020032import android.graphics.Bitmap;
Adrian Roosccdff622014-08-06 00:07:18 +020033import android.graphics.drawable.Drawable;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020034import android.os.AsyncTask;
Jason Monk2daf62c2014-07-31 14:35:06 -040035import android.os.Handler;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020036import android.os.RemoteException;
Adrian Roose9c7d432014-07-17 18:27:38 +020037import android.os.UserHandle;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020038import android.os.UserManager;
Jason Monk2daf62c2014-07-31 14:35:06 -040039import android.provider.Settings;
Fyodor Kupolov523c4042016-02-24 15:03:13 -080040import android.telephony.PhoneStateListener;
41import android.telephony.TelephonyManager;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020042import android.util.Log;
Adrian Roose9c7d432014-07-17 18:27:38 +020043import android.util.SparseArray;
Adrian Roos88b11932015-07-22 14:59:48 -070044import android.util.SparseBooleanArray;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020045import android.view.View;
46import android.view.ViewGroup;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020047import android.widget.BaseAdapter;
48
Chris Wrenf6e9228b2016-01-26 18:04:35 -050049import com.android.internal.logging.MetricsProto.MetricsEvent;
Alexandra Gherghina64d4dca2014-08-28 18:26:56 +010050import com.android.internal.util.UserIcons;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000051import com.android.settingslib.RestrictedLockUtils;
Alexandra Gherghina64d4dca2014-08-28 18:26:56 +010052import com.android.systemui.BitmapHelper;
53import com.android.systemui.GuestResumeSessionReceiver;
54import com.android.systemui.R;
55import com.android.systemui.qs.QSTile;
56import com.android.systemui.qs.tiles.UserDetailView;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000057import com.android.systemui.statusbar.phone.ActivityStarter;
Alexandra Gherghina64d4dca2014-08-28 18:26:56 +010058import com.android.systemui.statusbar.phone.SystemUIDialog;
59
Adrian Roos00a0b1f2014-07-16 16:44:49 +020060import java.io.FileDescriptor;
61import java.io.PrintWriter;
62import java.lang.ref.WeakReference;
63import java.util.ArrayList;
64import java.util.List;
65
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000066import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
67
Adrian Roos00a0b1f2014-07-16 16:44:49 +020068/**
69 * Keeps a list of all users on the device for user switching.
70 */
71public class UserSwitcherController {
72
73 private static final String TAG = "UserSwitcherController";
Adrian Roos50052442014-07-17 23:35:18 +020074 private static final boolean DEBUG = false;
Jason Monk2daf62c2014-07-31 14:35:06 -040075 private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
76 "lockscreenSimpleUserSwitcher";
Fyodor Kupolovf4d6ad22015-04-13 11:52:18 -070077 private static final String ACTION_REMOVE_GUEST = "com.android.systemui.REMOVE_GUEST";
Xiaohui Chen860397f2015-07-22 15:03:48 -070078 private static final String ACTION_LOGOUT_USER = "com.android.systemui.LOGOUT_USER";
Adrian Roos88b11932015-07-22 14:59:48 -070079 private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020080
Amith Yamasanid81f8272015-07-23 17:15:45 -070081 private static final int ID_REMOVE_GUEST = 1010;
Xiaohui Chen860397f2015-07-22 15:03:48 -070082 private static final int ID_LOGOUT_USER = 1011;
Amith Yamasanid81f8272015-07-23 17:15:45 -070083 private static final String TAG_REMOVE_GUEST = "remove_guest";
Xiaohui Chen860397f2015-07-22 15:03:48 -070084 private static final String TAG_LOGOUT_USER = "logout_user";
85
Amith Yamasanid81f8272015-07-23 17:15:45 -070086 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
87
Adrian Roos00a0b1f2014-07-16 16:44:49 +020088 private final Context mContext;
89 private final UserManager mUserManager;
90 private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
Adrian Roos50052442014-07-17 23:35:18 +020091 private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
92 = new GuestResumeSessionReceiver();
Adrian Roosccdff622014-08-06 00:07:18 +020093 private final KeyguardMonitor mKeyguardMonitor;
Adrian Roos88b11932015-07-22 14:59:48 -070094 private final Handler mHandler;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +000095 private final ActivityStarter mActivityStarter;
Adrian Roos00a0b1f2014-07-16 16:44:49 +020096
97 private ArrayList<UserRecord> mUsers = new ArrayList<>();
Adrian Roos50052442014-07-17 23:35:18 +020098 private Dialog mExitGuestDialog;
Adrian Roos0c6763a2014-09-08 19:11:00 +020099 private Dialog mAddUserDialog;
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700100 private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
Adrian Roosccdff622014-08-06 00:07:18 +0200101 private boolean mSimpleUserSwitcher;
102 private boolean mAddUsersWhenLocked;
Adrian Roos88b11932015-07-22 14:59:48 -0700103 private boolean mPauseRefreshUsers;
104 private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200105
Adrian Roos88b11932015-07-22 14:59:48 -0700106 public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000107 Handler handler, ActivityStarter activityStarter) {
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200108 mContext = context;
Adrian Roos50052442014-07-17 23:35:18 +0200109 mGuestResumeSessionReceiver.register(context);
Adrian Roosccdff622014-08-06 00:07:18 +0200110 mKeyguardMonitor = keyguardMonitor;
Adrian Roos88b11932015-07-22 14:59:48 -0700111 mHandler = handler;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000112 mActivityStarter = activityStarter;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200113 mUserManager = UserManager.get(context);
114 IntentFilter filter = new IntentFilter();
115 filter.addAction(Intent.ACTION_USER_ADDED);
116 filter.addAction(Intent.ACTION_USER_REMOVED);
117 filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
118 filter.addAction(Intent.ACTION_USER_SWITCHED);
Adrian Roose9c7d432014-07-17 18:27:38 +0200119 filter.addAction(Intent.ACTION_USER_STOPPING);
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800120 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700121 mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
Adrian Roose9c7d432014-07-17 18:27:38 +0200122 null /* permission */, null /* scheduler */);
Jason Monk2daf62c2014-07-31 14:35:06 -0400123
Amith Yamasanid81f8272015-07-23 17:15:45 -0700124 filter = new IntentFilter();
125 filter.addAction(ACTION_REMOVE_GUEST);
Xiaohui Chen860397f2015-07-22 15:03:48 -0700126 filter.addAction(ACTION_LOGOUT_USER);
Amith Yamasani5891a342015-07-24 13:50:58 -0700127 mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
Amith Yamasanid81f8272015-07-23 17:15:45 -0700128 PERMISSION_SELF, null /* scheduler */);
Adrian Roosccdff622014-08-06 00:07:18 +0200129
Jason Monk2daf62c2014-07-31 14:35:06 -0400130 mContext.getContentResolver().registerContentObserver(
131 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
Adrian Roosccdff622014-08-06 00:07:18 +0200132 mSettingsObserver);
133 mContext.getContentResolver().registerContentObserver(
134 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
135 mSettingsObserver);
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800136 mContext.getContentResolver().registerContentObserver(
137 Settings.Global.getUriFor(
138 Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
139 true, mSettingsObserver);
Adrian Roosccdff622014-08-06 00:07:18 +0200140 // Fetch initial values.
141 mSettingsObserver.onChange(false);
142
143 keyguardMonitor.addCallback(mCallback);
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800144 listenForCallState();
Jason Monk2daf62c2014-07-31 14:35:06 -0400145
Adrian Roose9c7d432014-07-17 18:27:38 +0200146 refreshUsers(UserHandle.USER_NULL);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200147 }
148
Adrian Roose9c7d432014-07-17 18:27:38 +0200149 /**
150 * Refreshes users from UserManager.
151 *
152 * The pictures are only loaded if they have not been loaded yet.
153 *
154 * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
155 */
Amith Yamasani95ab7842014-08-11 17:09:26 -0700156 @SuppressWarnings("unchecked")
Adrian Roose9c7d432014-07-17 18:27:38 +0200157 private void refreshUsers(int forcePictureLoadForId) {
Adrian Roos88b11932015-07-22 14:59:48 -0700158 if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")");
159 if (forcePictureLoadForId != UserHandle.USER_NULL) {
160 mForcePictureLoadForUserId.put(forcePictureLoadForId, true);
161 }
162
163 if (mPauseRefreshUsers) {
164 return;
165 }
Adrian Roosc5db3902014-11-21 13:54:04 +0000166
167 SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
168 final int N = mUsers.size();
169 for (int i = 0; i < N; i++) {
170 UserRecord r = mUsers.get(i);
Adrian Roos88b11932015-07-22 14:59:48 -0700171 if (r == null || r.picture == null ||
172 r.info == null || mForcePictureLoadForUserId.get(r.info.id)) {
Adrian Roosc5db3902014-11-21 13:54:04 +0000173 continue;
Adrian Roose9c7d432014-07-17 18:27:38 +0200174 }
Adrian Roosc5db3902014-11-21 13:54:04 +0000175 bitmaps.put(r.info.id, r.picture);
Adrian Roose9c7d432014-07-17 18:27:38 +0200176 }
Adrian Roos88b11932015-07-22 14:59:48 -0700177 mForcePictureLoadForUserId.clear();
Adrian Roose9c7d432014-07-17 18:27:38 +0200178
Adrian Roosccdff622014-08-06 00:07:18 +0200179 final boolean addUsersWhenLocked = mAddUsersWhenLocked;
Adrian Roose9c7d432014-07-17 18:27:38 +0200180 new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
181 @SuppressWarnings("unchecked")
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200182 @Override
Adrian Roose9c7d432014-07-17 18:27:38 +0200183 protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
184 final SparseArray<Bitmap> bitmaps = params[0];
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200185 List<UserInfo> infos = mUserManager.getUsers(true);
186 if (infos == null) {
187 return null;
188 }
189 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
190 int currentId = ActivityManager.getCurrentUser();
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800191 boolean canSwitchUsers = mUserManager.canSwitchUsers();
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700192 UserInfo currentUserInfo = null;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200193 UserRecord guestRecord = null;
Dan Sandler4d75c072014-07-17 16:01:28 -0400194 int avatarSize = mContext.getResources()
195 .getDimensionPixelSize(R.dimen.max_avatar_size);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200196
197 for (UserInfo info : infos) {
198 boolean isCurrent = currentId == info.id;
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700199 if (isCurrent) {
200 currentUserInfo = info;
201 }
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800202 boolean switchToEnabled = canSwitchUsers || isCurrent;
Lenka Trochtova1ddda472016-02-12 10:42:12 +0100203 if (info.isEnabled()) {
204 if (info.isGuest()) {
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800205 // Tapping guest icon triggers remove and a user switch therefore
206 // the icon shouldn't be enabled even if the user is current
Lenka Trochtova1ddda472016-02-12 10:42:12 +0100207 guestRecord = new UserRecord(info, null /* picture */,
208 true /* isGuest */, isCurrent, false /* isAddUser */,
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800209 false /* isRestricted */, canSwitchUsers);
Lenka Trochtova1ddda472016-02-12 10:42:12 +0100210 } else if (info.supportsSwitchToByUser()) {
211 Bitmap picture = bitmaps.get(info.id);
212 if (picture == null) {
213 picture = mUserManager.getUserIcon(info.id);
Adrian Rooscba0faa2014-11-17 17:41:28 +0100214
Lenka Trochtova1ddda472016-02-12 10:42:12 +0100215 if (picture != null) {
216 picture = BitmapHelper.createCircularClip(
217 picture, avatarSize, avatarSize);
218 }
Adrian Rooscba0faa2014-11-17 17:41:28 +0100219 }
Lenka Trochtova1ddda472016-02-12 10:42:12 +0100220 int index = isCurrent ? 0 : records.size();
221 records.add(index, new UserRecord(info, picture, false /* isGuest */,
222 isCurrent, false /* isAddUser */, false /* isRestricted */,
223 switchToEnabled));
Dan Sandler4d75c072014-07-17 16:01:28 -0400224 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200225 }
226 }
227
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000228 boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
229 UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700230 boolean currentUserCanCreateUsers = currentUserInfo != null
231 && (currentUserInfo.isAdmin()
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000232 || currentUserInfo.id == UserHandle.USER_SYSTEM)
233 && systemCanCreateUsers;
234 boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
235 boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
Adrian Roosccdff622014-08-06 00:07:18 +0200236 && guestRecord == null;
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000237 boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
Amith Yamasani95ab7842014-08-11 17:09:26 -0700238 && mUserManager.canAddMoreUsers();
Adrian Roosccdff622014-08-06 00:07:18 +0200239 boolean createIsRestricted = !addUsersWhenLocked;
240
Jason Monk2daf62c2014-07-31 14:35:06 -0400241 if (!mSimpleUserSwitcher) {
242 if (guestRecord == null) {
Adrian Roosccdff622014-08-06 00:07:18 +0200243 if (canCreateGuest) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000244 guestRecord = new UserRecord(null /* info */, null /* picture */,
Adrian Roosccdff622014-08-06 00:07:18 +0200245 true /* isGuest */, false /* isCurrent */,
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800246 false /* isAddUser */, createIsRestricted, canSwitchUsers);
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000247 checkIfAddUserDisallowedByAdminOnly(guestRecord);
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000248 records.add(guestRecord);
Adrian Roosccdff622014-08-06 00:07:18 +0200249 }
Jason Monk2daf62c2014-07-31 14:35:06 -0400250 } else {
Adrian Roosbed6e3b2014-08-21 20:31:41 +0200251 int index = guestRecord.isCurrent ? 0 : records.size();
252 records.add(index, guestRecord);
Jason Monk2daf62c2014-07-31 14:35:06 -0400253 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200254 }
255
Jason Monk092be7d2014-09-02 15:26:13 -0400256 if (!mSimpleUserSwitcher && canCreateUser) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000257 UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
Adrian Roosccdff622014-08-06 00:07:18 +0200258 false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800259 createIsRestricted, canSwitchUsers);
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000260 checkIfAddUserDisallowedByAdminOnly(addUserRecord);
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000261 records.add(addUserRecord);
Adrian Roosccdff622014-08-06 00:07:18 +0200262 }
263
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200264 return records;
265 }
266
267 @Override
268 protected void onPostExecute(ArrayList<UserRecord> userRecords) {
269 if (userRecords != null) {
270 mUsers = userRecords;
271 notifyAdapters();
272 }
273 }
Adrian Roosccdff622014-08-06 00:07:18 +0200274 }.execute((SparseArray) bitmaps);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200275 }
276
Adrian Roos88b11932015-07-22 14:59:48 -0700277 private void pauseRefreshUsers() {
278 if (!mPauseRefreshUsers) {
279 mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS);
280 mPauseRefreshUsers = true;
281 }
282 }
283
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200284 private void notifyAdapters() {
285 for (int i = mAdapters.size() - 1; i >= 0; i--) {
286 BaseUserAdapter adapter = mAdapters.get(i).get();
287 if (adapter != null) {
288 adapter.notifyDataSetChanged();
289 } else {
290 mAdapters.remove(i);
291 }
292 }
293 }
294
Jason Monk2daf62c2014-07-31 14:35:06 -0400295 public boolean isSimpleUserSwitcher() {
296 return mSimpleUserSwitcher;
297 }
298
Xiyuan Xiacc3a74f62015-07-22 14:16:34 -0700299 public boolean useFullscreenUserSwitcher() {
300 // Use adb to override:
301 // adb shell settings put system enable_fullscreen_user_switcher 0 # Turn it off.
302 // adb shell settings put system enable_fullscreen_user_switcher 1 # Turn it on.
303 // Restart SystemUI or adb reboot.
304 final int DEFAULT = -1;
305 final int overrideUseFullscreenUserSwitcher =
306 Settings.System.getInt(mContext.getContentResolver(),
307 "enable_fullscreen_user_switcher", DEFAULT);
308 if (overrideUseFullscreenUserSwitcher != DEFAULT) {
309 return overrideUseFullscreenUserSwitcher != 0;
310 }
311 // Otherwise default to the build setting.
Xiyuan Xia40f9dab2015-08-17 13:19:30 -0700312 return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
Xiyuan Xiacc3a74f62015-07-22 14:16:34 -0700313 }
314
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800315 public void logoutCurrentUser() {
316 int currentUser = ActivityManager.getCurrentUser();
317 if (currentUser != UserHandle.USER_SYSTEM) {
318 switchToUserId(UserHandle.USER_SYSTEM);
319 stopUserId(currentUser);
320 }
321 }
322
Xiyuan Xiacc3a74f62015-07-22 14:16:34 -0700323 public void removeUserId(int userId) {
324 if (userId == UserHandle.USER_SYSTEM) {
325 Log.w(TAG, "User " + userId + " could not removed.");
326 return;
327 }
328 if (ActivityManager.getCurrentUser() == userId) {
329 switchToUserId(UserHandle.USER_SYSTEM);
330 }
331 if (mUserManager.removeUser(userId)) {
332 refreshUsers(UserHandle.USER_NULL);
333 }
334 }
335
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200336 public void switchTo(UserRecord record) {
337 int id;
338 if (record.isGuest && record.info == null) {
339 // No guest user. Create one.
Adrian Roosf99727c2014-09-17 16:15:07 +0200340 UserInfo guest = mUserManager.createGuest(
341 mContext, mContext.getString(R.string.guest_nickname));
342 if (guest == null) {
343 // Couldn't create guest, most likely because there already exists one, we just
344 // haven't reloaded the user list yet.
345 return;
346 }
347 id = guest.id;
Adrian Roosccdff622014-08-06 00:07:18 +0200348 } else if (record.isAddUser) {
Adrian Roos0c6763a2014-09-08 19:11:00 +0200349 showAddUserDialog();
350 return;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200351 } else {
352 id = record.info.id;
353 }
354
355 if (ActivityManager.getCurrentUser() == id) {
Adrian Roose9c7d432014-07-17 18:27:38 +0200356 if (record.isGuest) {
Adrian Roos50052442014-07-17 23:35:18 +0200357 showExitGuestDialog(id);
Adrian Roose9c7d432014-07-17 18:27:38 +0200358 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200359 return;
360 }
361
Adrian Roose9c7d432014-07-17 18:27:38 +0200362 switchToUserId(id);
363 }
364
Fyodor Kupolovcaab2662016-03-01 18:39:27 -0800365 public void switchTo(int userId) {
366 final int count = mUsers.size();
367 for (int i = 0; i < count; ++i) {
368 UserRecord record = mUsers.get(i);
369 if (record.info != null && record.info.id == userId) {
370 switchTo(record);
371 return;
372 }
373 }
374
375 Log.e(TAG, "Couldn't switch to user, id=" + userId);
376 }
377
Adrian Roose9c7d432014-07-17 18:27:38 +0200378 private void switchToUserId(int id) {
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200379 try {
Adrian Roos88b11932015-07-22 14:59:48 -0700380 pauseRefreshUsers();
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200381 ActivityManagerNative.getDefault().switchUser(id);
382 } catch (RemoteException e) {
383 Log.e(TAG, "Couldn't switch user.", e);
384 }
385 }
386
Xiaohui Chen860397f2015-07-22 15:03:48 -0700387 private void stopUserId(int id) {
388 try {
Fyodor Kupolov9cbfc9e2015-10-07 15:52:33 -0700389 ActivityManagerNative.getDefault().stopUser(id, /* force= */ false, null);
Xiaohui Chen860397f2015-07-22 15:03:48 -0700390 } catch (RemoteException e) {
391 Log.e(TAG, "Couldn't stop user.", e);
392 }
393 }
394
Adrian Roos50052442014-07-17 23:35:18 +0200395 private void showExitGuestDialog(int id) {
396 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
397 mExitGuestDialog.cancel();
398 }
399 mExitGuestDialog = new ExitGuestDialog(mContext, id);
400 mExitGuestDialog.show();
401 }
402
Adrian Roos0c6763a2014-09-08 19:11:00 +0200403 private void showAddUserDialog() {
404 if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
405 mAddUserDialog.cancel();
406 }
407 mAddUserDialog = new AddUserDialog(mContext);
408 mAddUserDialog.show();
409 }
410
Adrian Roose9c7d432014-07-17 18:27:38 +0200411 private void exitGuest(int id) {
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700412 int newId = UserHandle.USER_SYSTEM;
413 if (mLastNonGuestUser != UserHandle.USER_SYSTEM) {
Adrian Roos70441462014-07-22 16:03:12 +0200414 UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700415 if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
Adrian Roos70441462014-07-22 16:03:12 +0200416 newId = info.id;
417 }
418 }
419 switchToUserId(newId);
Adrian Roose9c7d432014-07-17 18:27:38 +0200420 mUserManager.removeUser(id);
421 }
422
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800423 private void listenForCallState() {
424 TelephonyManager.from(mContext).listen(new PhoneStateListener() {
425 private int mCallState;
426 @Override
427 public void onCallStateChanged(int state, String incomingNumber) {
428 if (mCallState == state) return;
429 if (DEBUG) Log.v(TAG, "Call state changed: " + state);
430 mCallState = state;
431 int currentUserId = ActivityManager.getCurrentUser();
432 UserInfo userInfo = mUserManager.getUserInfo(currentUserId);
433 if (userInfo != null && userInfo.isGuest()) {
434 showGuestNotification(currentUserId);
435 }
436 refreshUsers(UserHandle.USER_NULL);
437 }
438 }, PhoneStateListener.LISTEN_CALL_STATE);
439 }
440
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200441 private BroadcastReceiver mReceiver = new BroadcastReceiver() {
442 @Override
443 public void onReceive(Context context, Intent intent) {
Adrian Roos50052442014-07-17 23:35:18 +0200444 if (DEBUG) {
445 Log.v(TAG, "Broadcast: a=" + intent.getAction()
446 + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
447 }
Adrian Roos88b11932015-07-22 14:59:48 -0700448
449 boolean unpauseRefreshUsers = false;
450 int forcePictureLoadForId = UserHandle.USER_NULL;
451
Fyodor Kupolovf4d6ad22015-04-13 11:52:18 -0700452 if (ACTION_REMOVE_GUEST.equals(intent.getAction())) {
453 int currentUser = ActivityManager.getCurrentUser();
454 UserInfo userInfo = mUserManager.getUserInfo(currentUser);
455 if (userInfo != null && userInfo.isGuest()) {
456 showExitGuestDialog(currentUser);
457 }
458 return;
Adrian Roos80996bb2015-07-24 16:38:58 -0700459 } else if (ACTION_LOGOUT_USER.equals(intent.getAction())) {
Xiyuan Xia1b30f792016-01-06 08:50:30 -0800460 logoutCurrentUser();
Adrian Roos88b11932015-07-22 14:59:48 -0700461 } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
Adrian Roos50052442014-07-17 23:35:18 +0200462 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
463 mExitGuestDialog.cancel();
464 mExitGuestDialog = null;
465 }
466
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200467 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700468 final UserInfo userInfo = mUserManager.getUserInfo(currentId);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200469 final int N = mUsers.size();
470 for (int i = 0; i < N; i++) {
471 UserRecord record = mUsers.get(i);
Adrian Roose9c7d432014-07-17 18:27:38 +0200472 if (record.info == null) continue;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200473 boolean shouldBeCurrent = record.info.id == currentId;
474 if (record.isCurrent != shouldBeCurrent) {
475 mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
476 }
Adrian Roos70441462014-07-22 16:03:12 +0200477 if (shouldBeCurrent && !record.isGuest) {
478 mLastNonGuestUser = record.info.id;
479 }
Xiaohui Chen7cb69df2015-07-13 16:01:01 -0700480 if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) {
Adrian Roosccdff622014-08-06 00:07:18 +0200481 // Immediately remove restricted records in case the AsyncTask is too slow.
482 mUsers.remove(i);
483 i--;
484 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200485 }
486 notifyAdapters();
Xiaohui Chen860397f2015-07-22 15:03:48 -0700487
488 if (UserManager.isSplitSystemUser() && userInfo != null && !userInfo.isGuest()
489 && userInfo.id != UserHandle.USER_SYSTEM) {
490 showLogoutNotification(currentId);
491 }
Fyodor Kupolovce161862015-08-18 12:41:52 -0700492 if (userInfo != null && userInfo.isGuest()) {
493 showGuestNotification(currentId);
494 }
Adrian Roos88b11932015-07-22 14:59:48 -0700495 unpauseRefreshUsers = true;
496 } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
Adrian Roose9c7d432014-07-17 18:27:38 +0200497 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
498 UserHandle.USER_NULL);
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800499 } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
500 // Unlocking the system user may require a refresh
501 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
502 if (userId != UserHandle.USER_SYSTEM) {
503 return;
504 }
Adrian Roose9c7d432014-07-17 18:27:38 +0200505 }
506 refreshUsers(forcePictureLoadForId);
Adrian Roos88b11932015-07-22 14:59:48 -0700507 if (unpauseRefreshUsers) {
508 mUnpauseRefreshUsers.run();
509 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200510 }
Fyodor Kupolovf4d6ad22015-04-13 11:52:18 -0700511
Xiaohui Chen860397f2015-07-22 15:03:48 -0700512 private void showLogoutNotification(int userId) {
513 PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
514 0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
515 Notification notification = new Notification.Builder(mContext)
516 .setVisibility(Notification.VISIBILITY_SECRET)
517 .setPriority(Notification.PRIORITY_MIN)
518 .setSmallIcon(R.drawable.ic_person)
519 .setContentTitle(mContext.getString(R.string.user_logout_notification_title))
520 .setContentText(mContext.getString(R.string.user_logout_notification_text))
Fyodor Kupolov52408f42015-08-17 16:34:07 -0700521 .setContentIntent(logoutPI)
Fyodor Kupolovce161862015-08-18 12:41:52 -0700522 .setOngoing(true)
Xiaohui Chen860397f2015-07-22 15:03:48 -0700523 .setShowWhen(false)
524 .addAction(R.drawable.ic_delete,
525 mContext.getString(R.string.user_logout_notification_action),
526 logoutPI)
527 .build();
528 NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER, ID_LOGOUT_USER,
529 notification, new UserHandle(userId));
530 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200531 };
532
Fyodor Kupolov523c4042016-02-24 15:03:13 -0800533 private void showGuestNotification(int guestUserId) {
534 boolean canSwitchUsers = mUserManager.canSwitchUsers();
535 // Disable 'Remove guest' action if cannot switch users right now
536 PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
537 0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
538
539 Notification notification = new Notification.Builder(mContext)
540 .setVisibility(Notification.VISIBILITY_SECRET)
541 .setPriority(Notification.PRIORITY_MIN)
542 .setSmallIcon(R.drawable.ic_person)
543 .setContentTitle(mContext.getString(R.string.guest_notification_title))
544 .setContentText(mContext.getString(R.string.guest_notification_text))
545 .setContentIntent(removeGuestPI)
546 .setShowWhen(false)
547 .addAction(R.drawable.ic_delete,
548 mContext.getString(R.string.guest_notification_remove_action),
549 removeGuestPI)
550 .build();
551 NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
552 notification, new UserHandle(guestUserId));
553 }
554
Adrian Roos88b11932015-07-22 14:59:48 -0700555 private final Runnable mUnpauseRefreshUsers = new Runnable() {
556 @Override
557 public void run() {
558 mHandler.removeCallbacks(this);
559 mPauseRefreshUsers = false;
560 refreshUsers(UserHandle.USER_NULL);
561 }
562 };
563
Adrian Roosccdff622014-08-06 00:07:18 +0200564 private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
Jason Monk2daf62c2014-07-31 14:35:06 -0400565 public void onChange(boolean selfChange) {
566 mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
567 SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
Adrian Roosccdff622014-08-06 00:07:18 +0200568 mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
569 Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
Jason Monk2daf62c2014-07-31 14:35:06 -0400570 refreshUsers(UserHandle.USER_NULL);
571 };
572 };
573
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200574 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
575 pw.println("UserSwitcherController state:");
Adrian Roos70441462014-07-22 16:03:12 +0200576 pw.println(" mLastNonGuestUser=" + mLastNonGuestUser);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200577 pw.print(" mUsers.size="); pw.println(mUsers.size());
578 for (int i = 0; i < mUsers.size(); i++) {
579 final UserRecord u = mUsers.get(i);
580 pw.print(" "); pw.println(u.toString());
581 }
582 }
583
Adrian Roos57cf5702014-09-03 15:56:30 +0200584 public String getCurrentUserName(Context context) {
585 if (mUsers.isEmpty()) return null;
586 UserRecord item = mUsers.get(0);
587 if (item == null || item.info == null) return null;
588 if (item.isGuest) return context.getString(R.string.guest_nickname);
589 return item.info.name;
590 }
591
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200592 public static abstract class BaseUserAdapter extends BaseAdapter {
593
594 final UserSwitcherController mController;
595
596 protected BaseUserAdapter(UserSwitcherController controller) {
597 mController = controller;
598 controller.mAdapters.add(new WeakReference<>(this));
599 }
600
601 @Override
602 public int getCount() {
Adrian Roosccdff622014-08-06 00:07:18 +0200603 boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
Jason Monk8a3a9642015-06-05 11:01:30 -0400604 && mController.mKeyguardMonitor.isSecure()
Selim Cineke8bae622015-07-15 13:24:06 -0700605 && !mController.mKeyguardMonitor.canSkipBouncer();
Adrian Roosccdff622014-08-06 00:07:18 +0200606 if (!secureKeyguardShowing) {
607 return mController.mUsers.size();
608 }
609 // The lock screen is secure and showing. Filter out restricted records.
610 final int N = mController.mUsers.size();
611 int count = 0;
612 for (int i = 0; i < N; i++) {
613 if (mController.mUsers.get(i).isRestricted) {
614 break;
615 } else {
616 count++;
617 }
618 }
619 return count;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200620 }
621
622 @Override
623 public UserRecord getItem(int position) {
624 return mController.mUsers.get(position);
625 }
626
627 @Override
628 public long getItemId(int position) {
Adrian Roose9c7d432014-07-17 18:27:38 +0200629 return position;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200630 }
631
632 public void switchTo(UserRecord record) {
633 mController.switchTo(record);
634 }
Adrian Roose9c7d432014-07-17 18:27:38 +0200635
636 public String getName(Context context, UserRecord item) {
637 if (item.isGuest) {
638 if (item.isCurrent) {
639 return context.getString(R.string.guest_exit_guest);
640 } else {
641 return context.getString(
642 item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
643 }
Adrian Roosccdff622014-08-06 00:07:18 +0200644 } else if (item.isAddUser) {
645 return context.getString(R.string.user_add_user);
Adrian Roose9c7d432014-07-17 18:27:38 +0200646 } else {
647 return item.info.name;
648 }
649 }
Adrian Roos723632e2014-07-23 21:13:21 +0200650
Adrian Roosccdff622014-08-06 00:07:18 +0200651 public Drawable getDrawable(Context context, UserRecord item) {
652 if (item.isAddUser) {
653 return context.getDrawable(R.drawable.ic_add_circle_qs);
654 }
Alexandra Gherghina64d4dca2014-08-28 18:26:56 +0100655 return UserIcons.getDefaultUserIcon(item.isGuest ? UserHandle.USER_NULL : item.info.id,
656 /* light= */ true);
Adrian Roosccdff622014-08-06 00:07:18 +0200657 }
Adrian Roos844c92b2014-12-01 14:19:05 +0100658
659 public void refresh() {
660 mController.refreshUsers(UserHandle.USER_NULL);
661 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200662 }
663
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000664 private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000665 EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
Sudheer Shankab6fc9312016-01-27 19:59:03 +0000666 UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
Sudheer Shankaa8fbbb32016-02-11 17:17:57 +0000667 if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
668 UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000669 record.isDisabledByAdmin = true;
670 record.enforcedAdmin = admin;
671 } else {
672 record.isDisabledByAdmin = false;
673 record.enforcedAdmin = null;
674 }
675 }
676
677 public void startActivity(Intent intent) {
678 mActivityStarter.startActivity(intent, true);
679 }
680
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200681 public static final class UserRecord {
682 public final UserInfo info;
683 public final Bitmap picture;
684 public final boolean isGuest;
685 public final boolean isCurrent;
Adrian Roosccdff622014-08-06 00:07:18 +0200686 public final boolean isAddUser;
687 /** If true, the record is only visible to the owner and only when unlocked. */
688 public final boolean isRestricted;
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000689 public boolean isDisabledByAdmin;
690 public EnforcedAdmin enforcedAdmin;
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800691 public boolean isSwitchToEnabled;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200692
Adrian Roosccdff622014-08-06 00:07:18 +0200693 public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800694 boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200695 this.info = info;
696 this.picture = picture;
697 this.isGuest = isGuest;
698 this.isCurrent = isCurrent;
Adrian Roosccdff622014-08-06 00:07:18 +0200699 this.isAddUser = isAddUser;
700 this.isRestricted = isRestricted;
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800701 this.isSwitchToEnabled = isSwitchToEnabled;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200702 }
703
704 public UserRecord copyWithIsCurrent(boolean _isCurrent) {
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800705 return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
706 isSwitchToEnabled);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200707 }
708
709 public String toString() {
710 StringBuilder sb = new StringBuilder();
711 sb.append("UserRecord(");
712 if (info != null) {
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800713 sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200714 } else {
Adrian Roosccdff622014-08-06 00:07:18 +0200715 if (isGuest) {
716 sb.append("<add guest placeholder>");
717 } else if (isAddUser) {
718 sb.append("<add user placeholder>");
719 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200720 }
Adrian Roosccdff622014-08-06 00:07:18 +0200721 if (isGuest) sb.append(" <isGuest>");
722 if (isAddUser) sb.append(" <isAddUser>");
723 if (isCurrent) sb.append(" <isCurrent>");
724 if (picture != null) sb.append(" <hasPicture>");
725 if (isRestricted) sb.append(" <isRestricted>");
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000726 if (isDisabledByAdmin) {
727 sb.append(" <isDisabledByAdmin>");
Fyodor Kupolov07140f72016-02-17 10:46:11 -0800728 sb.append(" enforcedAdmin=").append(enforcedAdmin);
729 }
730 if (isSwitchToEnabled) {
731 sb.append(" <isSwitchToEnabled>");
Sudheer Shanka1c7cda82015-12-31 14:46:02 +0000732 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200733 sb.append(')');
734 return sb.toString();
735 }
736 }
737
738 public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
Jason Monk76c67aa2016-02-19 14:49:42 -0500739 private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200740
741 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500742 public CharSequence getTitle() {
743 return mContext.getString(R.string.quick_settings_user_title);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200744 }
745
746 @Override
747 public View createDetailView(Context context, View convertView, ViewGroup parent) {
Adrian Roos19408922014-08-07 20:54:12 +0200748 UserDetailView v;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200749 if (!(convertView instanceof UserDetailView)) {
Adrian Roos19408922014-08-07 20:54:12 +0200750 v = UserDetailView.inflate(context, parent, false);
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200751 v.createAndSetAdapter(UserSwitcherController.this);
Adrian Roos19408922014-08-07 20:54:12 +0200752 } else {
753 v = (UserDetailView) convertView;
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200754 }
Adrian Roos844c92b2014-12-01 14:19:05 +0100755 v.refreshAdapter();
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200756 return v;
757 }
758
759 @Override
760 public Intent getSettingsIntent() {
761 return USER_SETTINGS_INTENT;
762 }
763
764 @Override
765 public Boolean getToggleState() {
766 return null;
767 }
768
769 @Override
770 public void setToggleState(boolean state) {
771 }
Chris Wren457a21c2015-05-06 17:50:34 -0400772
773 @Override
774 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500775 return MetricsEvent.QS_USERDETAIL;
Chris Wren457a21c2015-05-06 17:50:34 -0400776 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200777 };
Adrian Roos50052442014-07-17 23:35:18 +0200778
Adrian Roosccdff622014-08-06 00:07:18 +0200779 private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
780 @Override
781 public void onKeyguardChanged() {
782 notifyAdapters();
783 }
784 };
785
Adrian Roos50052442014-07-17 23:35:18 +0200786 private final class ExitGuestDialog extends SystemUIDialog implements
787 DialogInterface.OnClickListener {
788
789 private final int mGuestId;
790
791 public ExitGuestDialog(Context context, int guestId) {
792 super(context);
793 setTitle(R.string.guest_exit_guest_dialog_title);
794 setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
795 setButton(DialogInterface.BUTTON_NEGATIVE,
Amith Yamasanie5b274a2014-08-18 07:57:56 -0700796 context.getString(android.R.string.cancel), this);
Adrian Roos50052442014-07-17 23:35:18 +0200797 setButton(DialogInterface.BUTTON_POSITIVE,
Amith Yamasanie5b274a2014-08-18 07:57:56 -0700798 context.getString(R.string.guest_exit_guest_dialog_remove), this);
Adrian Roos50052442014-07-17 23:35:18 +0200799 setCanceledOnTouchOutside(false);
800 mGuestId = guestId;
801 }
802
803 @Override
804 public void onClick(DialogInterface dialog, int which) {
805 if (which == BUTTON_NEGATIVE) {
806 cancel();
807 } else {
808 dismiss();
809 exitGuest(mGuestId);
810 }
811 }
812 }
Adrian Roos0c6763a2014-09-08 19:11:00 +0200813
814 private final class AddUserDialog extends SystemUIDialog implements
815 DialogInterface.OnClickListener {
816
817 public AddUserDialog(Context context) {
818 super(context);
819 setTitle(R.string.user_add_user_title);
820 setMessage(context.getString(R.string.user_add_user_message_short));
821 setButton(DialogInterface.BUTTON_NEGATIVE,
822 context.getString(android.R.string.cancel), this);
823 setButton(DialogInterface.BUTTON_POSITIVE,
824 context.getString(android.R.string.ok), this);
825 }
826
827 @Override
828 public void onClick(DialogInterface dialog, int which) {
829 if (which == BUTTON_NEGATIVE) {
830 cancel();
831 } else {
832 dismiss();
Guang Zhuccbeb612014-10-21 14:33:50 -0700833 if (ActivityManager.isUserAMonkey()) {
834 return;
835 }
Xiaohui Chencfe64c82015-07-16 14:30:50 -0700836 UserInfo user = mUserManager.createUser(
Adrian Roosf99727c2014-09-17 16:15:07 +0200837 mContext.getString(R.string.user_new_user_name), 0 /* flags */);
838 if (user == null) {
839 // Couldn't create user, most likely because there are too many, but we haven't
840 // been able to reload the list yet.
841 return;
842 }
843 int id = user.id;
Alexandra Gherghina64d4dca2014-08-28 18:26:56 +0100844 Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
845 id, /* light= */ false));
846 mUserManager.setUserIcon(id, icon);
Adrian Roos0c6763a2014-09-08 19:11:00 +0200847 switchToUserId(id);
848 }
849 }
850 }
Adrian Roos00a0b1f2014-07-16 16:44:49 +0200851}