1 /*
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 
17 package com.android.systemui.statusbar.policy;
18 
19 import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
20 
21 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
22 import static com.android.systemui.DejankUtils.whitelistIpcs;
23 
24 import android.annotation.UserIdInt;
25 import android.app.ActivityManager;
26 import android.app.AlertDialog;
27 import android.app.Dialog;
28 import android.app.IActivityManager;
29 import android.app.IActivityTaskManager;
30 import android.app.admin.DevicePolicyManager;
31 import android.content.BroadcastReceiver;
32 import android.content.Context;
33 import android.content.DialogInterface;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.pm.UserInfo;
37 import android.database.ContentObserver;
38 import android.graphics.Bitmap;
39 import android.graphics.ColorFilter;
40 import android.graphics.ColorMatrix;
41 import android.graphics.ColorMatrixColorFilter;
42 import android.graphics.drawable.Drawable;
43 import android.os.AsyncTask;
44 import android.os.Handler;
45 import android.os.RemoteException;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.provider.Settings;
49 import android.telephony.TelephonyCallback;
50 import android.util.Log;
51 import android.util.SparseArray;
52 import android.util.SparseBooleanArray;
53 import android.view.View;
54 import android.view.ViewGroup;
55 import android.view.WindowManagerGlobal;
56 import android.widget.BaseAdapter;
57 
58 import androidx.annotation.Nullable;
59 
60 import com.android.internal.annotations.VisibleForTesting;
61 import com.android.internal.jank.InteractionJankMonitor;
62 import com.android.internal.logging.UiEventLogger;
63 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
64 import com.android.internal.util.LatencyTracker;
65 import com.android.settingslib.RestrictedLockUtilsInternal;
66 import com.android.systemui.Dumpable;
67 import com.android.systemui.GuestResumeSessionReceiver;
68 import com.android.systemui.Prefs;
69 import com.android.systemui.Prefs.Key;
70 import com.android.systemui.R;
71 import com.android.systemui.SystemUISecondaryUserService;
72 import com.android.systemui.animation.DialogLaunchAnimator;
73 import com.android.systemui.broadcast.BroadcastDispatcher;
74 import com.android.systemui.dagger.SysUISingleton;
75 import com.android.systemui.dagger.qualifiers.Background;
76 import com.android.systemui.dagger.qualifiers.Main;
77 import com.android.systemui.dump.DumpManager;
78 import com.android.systemui.plugins.ActivityStarter;
79 import com.android.systemui.plugins.FalsingManager;
80 import com.android.systemui.plugins.qs.DetailAdapter;
81 import com.android.systemui.qs.QSUserSwitcherEvent;
82 import com.android.systemui.qs.tiles.UserDetailView;
83 import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower;
84 import com.android.systemui.settings.UserTracker;
85 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
86 import com.android.systemui.statusbar.phone.SystemUIDialog;
87 import com.android.systemui.telephony.TelephonyListenerManager;
88 import com.android.systemui.user.CreateUserActivity;
89 import com.android.systemui.util.settings.SecureSettings;
90 
91 import java.io.FileDescriptor;
92 import java.io.PrintWriter;
93 import java.lang.ref.WeakReference;
94 import java.util.ArrayList;
95 import java.util.List;
96 import java.util.concurrent.Executor;
97 import java.util.concurrent.atomic.AtomicBoolean;
98 
99 import javax.inject.Inject;
100 import javax.inject.Provider;
101 
102 /**
103  * Keeps a list of all users on the device for user switching.
104  */
105 @SysUISingleton
106 public class UserSwitcherController implements Dumpable {
107 
108     public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
109     public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
110 
111     private static final String TAG = "UserSwitcherController";
112     private static final boolean DEBUG = false;
113     private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
114             "lockscreenSimpleUserSwitcher";
115     private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
116 
117     private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
118     private static final long MULTI_USER_JOURNEY_TIMEOUT = 20000l;
119 
120     protected final Context mContext;
121     protected final UserTracker mUserTracker;
122     protected final UserManager mUserManager;
123     private final ContentObserver mSettingsObserver;
124     private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
125     @VisibleForTesting
126     final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
127     private final KeyguardStateController mKeyguardStateController;
128     private final DeviceProvisionedController mDeviceProvisionedController;
129     private final DevicePolicyManager mDevicePolicyManager;
130     protected final Handler mHandler;
131     private final ActivityStarter mActivityStarter;
132     private final BroadcastDispatcher mBroadcastDispatcher;
133     private final TelephonyListenerManager mTelephonyListenerManager;
134     private final IActivityTaskManager mActivityTaskManager;
135     private final InteractionJankMonitor mInteractionJankMonitor;
136     private final LatencyTracker mLatencyTracker;
137     private final DialogLaunchAnimator mDialogLaunchAnimator;
138 
139     private ArrayList<UserRecord> mUsers = new ArrayList<>();
140     @VisibleForTesting
141     AlertDialog mExitGuestDialog;
142     @VisibleForTesting
143     Dialog mAddUserDialog;
144     private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
145     private boolean mResumeUserOnGuestLogout = true;
146     private boolean mSimpleUserSwitcher;
147     // When false, there won't be any visual affordance to add a new user from the keyguard even if
148     // the user is unlocked
149     private boolean mAddUsersFromLockScreen;
150     @VisibleForTesting
151     boolean mPauseRefreshUsers;
152     private int mSecondaryUser = UserHandle.USER_NULL;
153     private Intent mSecondaryUserServiceIntent;
154     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
155     private final UiEventLogger mUiEventLogger;
156     private final IActivityManager mActivityManager;
157     public final DetailAdapter mUserDetailAdapter;
158     private final Executor mBgExecutor;
159     private final boolean mGuestUserAutoCreated;
160     private final AtomicBoolean mGuestIsResetting;
161     private final AtomicBoolean mGuestCreationScheduled;
162     private FalsingManager mFalsingManager;
163     private NotificationShadeWindowView mRootView;
164 
165     @Inject
UserSwitcherController(Context context, IActivityManager activityManager, UserManager userManager, UserTracker userTracker, KeyguardStateController keyguardStateController, DeviceProvisionedController deviceProvisionedController, DevicePolicyManager devicePolicyManager, @Main Handler handler, ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger, FalsingManager falsingManager, TelephonyListenerManager telephonyListenerManager, IActivityTaskManager activityTaskManager, UserDetailAdapter userDetailAdapter, SecureSettings secureSettings, @Background Executor bgExecutor, InteractionJankMonitor interactionJankMonitor, LatencyTracker latencyTracker, DumpManager dumpManager, DialogLaunchAnimator dialogLaunchAnimator)166     public UserSwitcherController(Context context,
167             IActivityManager activityManager,
168             UserManager userManager,
169             UserTracker userTracker,
170             KeyguardStateController keyguardStateController,
171             DeviceProvisionedController deviceProvisionedController,
172             DevicePolicyManager devicePolicyManager,
173             @Main Handler handler,
174             ActivityStarter activityStarter,
175             BroadcastDispatcher broadcastDispatcher,
176             UiEventLogger uiEventLogger,
177             FalsingManager falsingManager,
178             TelephonyListenerManager telephonyListenerManager,
179             IActivityTaskManager activityTaskManager,
180             UserDetailAdapter userDetailAdapter,
181             SecureSettings secureSettings,
182             @Background Executor bgExecutor,
183             InteractionJankMonitor interactionJankMonitor,
184             LatencyTracker latencyTracker,
185             DumpManager dumpManager,
186             DialogLaunchAnimator dialogLaunchAnimator) {
187         mContext = context;
188         mActivityManager = activityManager;
189         mUserTracker = userTracker;
190         mBroadcastDispatcher = broadcastDispatcher;
191         mTelephonyListenerManager = telephonyListenerManager;
192         mActivityTaskManager = activityTaskManager;
193         mUiEventLogger = uiEventLogger;
194         mFalsingManager = falsingManager;
195         mInteractionJankMonitor = interactionJankMonitor;
196         mLatencyTracker = latencyTracker;
197         mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(
198                 this, mUserTracker, mUiEventLogger, secureSettings);
199         mUserDetailAdapter = userDetailAdapter;
200         mBgExecutor = bgExecutor;
201         if (!UserManager.isGuestUserEphemeral()) {
202             mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
203         }
204         mGuestUserAutoCreated = mContext.getResources().getBoolean(
205                 com.android.internal.R.bool.config_guestUserAutoCreated);
206         mGuestIsResetting = new AtomicBoolean();
207         mGuestCreationScheduled = new AtomicBoolean();
208         mKeyguardStateController = keyguardStateController;
209         mDeviceProvisionedController = deviceProvisionedController;
210         mDevicePolicyManager = devicePolicyManager;
211         mHandler = handler;
212         mActivityStarter = activityStarter;
213         mUserManager = userManager;
214         mDialogLaunchAnimator = dialogLaunchAnimator;
215 
216         IntentFilter filter = new IntentFilter();
217         filter.addAction(Intent.ACTION_USER_ADDED);
218         filter.addAction(Intent.ACTION_USER_REMOVED);
219         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
220         filter.addAction(Intent.ACTION_USER_SWITCHED);
221         filter.addAction(Intent.ACTION_USER_STOPPED);
222         filter.addAction(Intent.ACTION_USER_UNLOCKED);
223         mBroadcastDispatcher.registerReceiver(
224                 mReceiver, filter, null /* handler */, UserHandle.SYSTEM);
225 
226         mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
227 
228         mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class);
229 
230         filter = new IntentFilter();
231         mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
232                 PERMISSION_SELF, null /* scheduler */);
233 
234         mSettingsObserver = new ContentObserver(mHandler) {
235             @Override
236             public void onChange(boolean selfChange) {
237                 mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
238                 mAddUsersFromLockScreen = Settings.Global.getInt(mContext.getContentResolver(),
239                         Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
240                 refreshUsers(UserHandle.USER_NULL);
241             };
242         };
243         mContext.getContentResolver().registerContentObserver(
244                 Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
245                 mSettingsObserver);
246         mContext.getContentResolver().registerContentObserver(
247                 Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
248                 mSettingsObserver);
249         mContext.getContentResolver().registerContentObserver(
250                 Settings.Global.getUriFor(
251                         Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
252                 true, mSettingsObserver);
253         // Fetch initial values.
254         mSettingsObserver.onChange(false);
255 
256         keyguardStateController.addCallback(mCallback);
257         listenForCallState();
258 
259         dumpManager.registerDumpable(getClass().getSimpleName(), this);
260 
261         refreshUsers(UserHandle.USER_NULL);
262     }
263 
264     /**
265      * Refreshes users from UserManager.
266      *
267      * The pictures are only loaded if they have not been loaded yet.
268      *
269      * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
270      */
271     @SuppressWarnings("unchecked")
refreshUsers(int forcePictureLoadForId)272     private void refreshUsers(int forcePictureLoadForId) {
273         if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")");
274         if (forcePictureLoadForId != UserHandle.USER_NULL) {
275             mForcePictureLoadForUserId.put(forcePictureLoadForId, true);
276         }
277 
278         if (mPauseRefreshUsers) {
279             return;
280         }
281 
282         boolean forceAllUsers = mForcePictureLoadForUserId.get(UserHandle.USER_ALL);
283         SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
284         final int N = mUsers.size();
285         for (int i = 0; i < N; i++) {
286             UserRecord r = mUsers.get(i);
287             if (r == null || r.picture == null || r.info == null || forceAllUsers
288                     || mForcePictureLoadForUserId.get(r.info.id)) {
289                 continue;
290             }
291             bitmaps.put(r.info.id, r.picture);
292         }
293         mForcePictureLoadForUserId.clear();
294 
295         final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
296         new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
297             @SuppressWarnings("unchecked")
298             @Override
299             protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
300                 final SparseArray<Bitmap> bitmaps = params[0];
301                 List<UserInfo> infos = mUserManager.getAliveUsers();
302                 if (infos == null) {
303                     return null;
304                 }
305                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
306                 int currentId = mUserTracker.getUserId();
307                 // Check user switchability of the foreground user since SystemUI is running in
308                 // User 0
309                 boolean canSwitchUsers = mUserManager.getUserSwitchability(
310                         UserHandle.of(mUserTracker.getUserId())) == SWITCHABILITY_STATUS_OK;
311                 UserInfo currentUserInfo = null;
312                 UserRecord guestRecord = null;
313 
314                 for (UserInfo info : infos) {
315                     boolean isCurrent = currentId == info.id;
316                     if (isCurrent) {
317                         currentUserInfo = info;
318                     }
319                     boolean switchToEnabled = canSwitchUsers || isCurrent;
320                     if (info.isEnabled()) {
321                         if (info.isGuest()) {
322                             // Tapping guest icon triggers remove and a user switch therefore
323                             // the icon shouldn't be enabled even if the user is current
324                             guestRecord = new UserRecord(info, null /* picture */,
325                                     true /* isGuest */, isCurrent, false /* isAddUser */,
326                                     false /* isRestricted */, canSwitchUsers);
327                         } else if (info.supportsSwitchToByUser()) {
328                             Bitmap picture = bitmaps.get(info.id);
329                             if (picture == null) {
330                                 picture = mUserManager.getUserIcon(info.id);
331 
332                                 if (picture != null) {
333                                     int avatarSize = mContext.getResources()
334                                             .getDimensionPixelSize(R.dimen.max_avatar_size);
335                                     picture = Bitmap.createScaledBitmap(
336                                             picture, avatarSize, avatarSize, true);
337                                 }
338                             }
339                             records.add(new UserRecord(info, picture, false /* isGuest */,
340                                     isCurrent, false /* isAddUser */, false /* isRestricted */,
341                                     switchToEnabled));
342                         }
343                     }
344                 }
345                 if (records.size() > 1 || guestRecord != null) {
346                     Prefs.putBoolean(mContext, Key.SEEN_MULTI_USER, true);
347                 }
348 
349                 boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
350                                 UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
351                 boolean currentUserCanCreateUsers = currentUserInfo != null
352                         && (currentUserInfo.isAdmin()
353                                 || currentUserInfo.id == UserHandle.USER_SYSTEM)
354                         && systemCanCreateUsers;
355                 boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
356                 boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
357                         && guestRecord == null;
358                 boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
359                         && mUserManager.canAddMoreUsers();
360                 boolean createIsRestricted = !addUsersWhenLocked;
361 
362                 if (guestRecord == null) {
363                     if (mGuestUserAutoCreated) {
364                         // If mGuestIsResetting=true, the switch should be disabled since
365                         // we will just use it as an indicator for "Resetting guest...".
366                         // Otherwise, default to canSwitchUsers.
367                         boolean isSwitchToGuestEnabled =
368                                 !mGuestIsResetting.get() && canSwitchUsers;
369                         guestRecord = new UserRecord(null /* info */, null /* picture */,
370                                 true /* isGuest */, false /* isCurrent */,
371                                 false /* isAddUser */, false /* isRestricted */,
372                                 isSwitchToGuestEnabled);
373                         checkIfAddUserDisallowedByAdminOnly(guestRecord);
374                         records.add(guestRecord);
375                     } else if (canCreateGuest) {
376                         guestRecord = new UserRecord(null /* info */, null /* picture */,
377                                 true /* isGuest */, false /* isCurrent */,
378                                 false /* isAddUser */, createIsRestricted, canSwitchUsers);
379                         checkIfAddUserDisallowedByAdminOnly(guestRecord);
380                         records.add(guestRecord);
381                     }
382                 } else {
383                     records.add(guestRecord);
384                 }
385 
386                 if (canCreateUser) {
387                     UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
388                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
389                             createIsRestricted, canSwitchUsers);
390                     checkIfAddUserDisallowedByAdminOnly(addUserRecord);
391                     records.add(addUserRecord);
392                 }
393 
394                 return records;
395             }
396 
397             @Override
398             protected void onPostExecute(ArrayList<UserRecord> userRecords) {
399                 if (userRecords != null) {
400                     mUsers = userRecords;
401                     notifyAdapters();
402                 }
403             }
404         }.execute((SparseArray) bitmaps);
405     }
406 
pauseRefreshUsers()407     private void pauseRefreshUsers() {
408         if (!mPauseRefreshUsers) {
409             mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS);
410             mPauseRefreshUsers = true;
411         }
412     }
413 
notifyAdapters()414     private void notifyAdapters() {
415         for (int i = mAdapters.size() - 1; i >= 0; i--) {
416             BaseUserAdapter adapter = mAdapters.get(i).get();
417             if (adapter != null) {
418                 adapter.notifyDataSetChanged();
419             } else {
420                 mAdapters.remove(i);
421             }
422         }
423     }
424 
isSimpleUserSwitcher()425     public boolean isSimpleUserSwitcher() {
426         return mSimpleUserSwitcher;
427     }
428 
useFullscreenUserSwitcher()429     public boolean useFullscreenUserSwitcher() {
430         // Use adb to override:
431         // adb shell settings put system enable_fullscreen_user_switcher 0  # Turn it off.
432         // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
433         // Restart SystemUI or adb reboot.
434         final int DEFAULT = -1;
435         final int overrideUseFullscreenUserSwitcher =
436                 whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(),
437                         "enable_fullscreen_user_switcher", DEFAULT));
438         if (overrideUseFullscreenUserSwitcher != DEFAULT) {
439             return overrideUseFullscreenUserSwitcher != 0;
440         }
441         // Otherwise default to the build setting.
442         return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
443     }
444 
setResumeUserOnGuestLogout(boolean resume)445     public void setResumeUserOnGuestLogout(boolean resume) {
446         mResumeUserOnGuestLogout = resume;
447     }
448 
logoutCurrentUser()449     public void logoutCurrentUser() {
450         int currentUser = mUserTracker.getUserId();
451         if (currentUser != UserHandle.USER_SYSTEM) {
452             pauseRefreshUsers();
453             ActivityManager.logoutCurrentUser();
454         }
455     }
456 
removeUserId(int userId)457     public void removeUserId(int userId) {
458         if (userId == UserHandle.USER_SYSTEM) {
459             Log.w(TAG, "User " + userId + " could not removed.");
460             return;
461         }
462         if (mUserTracker.getUserId() == userId) {
463             switchToUserId(UserHandle.USER_SYSTEM);
464         }
465         if (mUserManager.removeUser(userId)) {
466             refreshUsers(UserHandle.USER_NULL);
467         }
468     }
469 
470     @VisibleForTesting
onUserListItemClicked(UserRecord record, DialogShower dialogShower)471     void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
472         int id;
473         if (record.isGuest && record.info == null) {
474             // No guest user. Create one.
475             int guestId = createGuest();
476             if (guestId == UserHandle.USER_NULL) {
477                 // This may happen if we haven't reloaded the user list yet.
478                 return;
479             }
480             mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
481             id = guestId;
482         } else if (record.isAddUser) {
483             showAddUserDialog(dialogShower);
484             return;
485         } else {
486             id = record.info.id;
487         }
488 
489         int currUserId = mUserTracker.getUserId();
490         if (currUserId == id) {
491             if (record.isGuest) {
492                 showExitGuestDialog(id, dialogShower);
493             }
494             return;
495         }
496 
497         if (UserManager.isGuestUserEphemeral()) {
498             // If switching from guest, we want to bring up the guest exit dialog instead of switching
499             UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
500             if (currUserInfo != null && currUserInfo.isGuest()) {
501                 showExitGuestDialog(currUserId, record.resolveId(), dialogShower);
502                 return;
503             }
504         }
505         if (dialogShower != null) {
506             // If we haven't morphed into another dialog, it means we have just switched users.
507             // Then, dismiss the dialog.
508             dialogShower.dismiss();
509         }
510         switchToUserId(id);
511     }
512 
switchToUserId(int id)513     protected void switchToUserId(int id) {
514         try {
515             mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
516                     .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mRootView)
517                     .setTimeout(MULTI_USER_JOURNEY_TIMEOUT));
518             mLatencyTracker.onActionStart(LatencyTracker.ACTION_USER_SWITCH);
519             pauseRefreshUsers();
520             mActivityManager.switchUser(id);
521         } catch (RemoteException e) {
522             Log.e(TAG, "Couldn't switch user.", e);
523         }
524     }
525 
showExitGuestDialog(int id, DialogShower dialogShower)526     private void showExitGuestDialog(int id, DialogShower dialogShower) {
527         int newId = UserHandle.USER_SYSTEM;
528         if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
529             UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
530             if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
531                 newId = info.id;
532             }
533         }
534         showExitGuestDialog(id, newId, dialogShower);
535     }
536 
showExitGuestDialog(int id, int targetId, DialogShower dialogShower)537     private void showExitGuestDialog(int id, int targetId, DialogShower dialogShower) {
538         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
539             mExitGuestDialog.cancel();
540         }
541         mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId);
542         if (dialogShower != null) {
543             dialogShower.showDialog(mExitGuestDialog);
544         } else {
545             mExitGuestDialog.show();
546         }
547     }
548 
showAddUserDialog(DialogShower dialogShower)549     private void showAddUserDialog(DialogShower dialogShower) {
550         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
551             mAddUserDialog.cancel();
552         }
553         mAddUserDialog = new AddUserDialog(mContext);
554         if (dialogShower != null) {
555             dialogShower.showDialog(mAddUserDialog);
556         } else {
557             mAddUserDialog.show();
558         }
559     }
560 
listenForCallState()561     private void listenForCallState() {
562         mTelephonyListenerManager.addCallStateListener(mPhoneStateListener);
563     }
564 
565     private final TelephonyCallback.CallStateListener mPhoneStateListener =
566             new TelephonyCallback.CallStateListener() {
567         private int mCallState;
568 
569         @Override
570         public void onCallStateChanged(int state) {
571             if (mCallState == state) return;
572             if (DEBUG) Log.v(TAG, "Call state changed: " + state);
573             mCallState = state;
574             refreshUsers(UserHandle.USER_NULL);
575         }
576     };
577 
578     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
579         @Override
580         public void onReceive(Context context, Intent intent) {
581             if (DEBUG) {
582                 Log.v(TAG, "Broadcast: a=" + intent.getAction()
583                        + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
584             }
585 
586             boolean unpauseRefreshUsers = false;
587             int forcePictureLoadForId = UserHandle.USER_NULL;
588 
589             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
590                 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
591                     mExitGuestDialog.cancel();
592                     mExitGuestDialog = null;
593                 }
594 
595                 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
596                 final UserInfo userInfo = mUserManager.getUserInfo(currentId);
597                 final int N = mUsers.size();
598                 for (int i = 0; i < N; i++) {
599                     UserRecord record = mUsers.get(i);
600                     if (record.info == null) continue;
601                     boolean shouldBeCurrent = record.info.id == currentId;
602                     if (record.isCurrent != shouldBeCurrent) {
603                         mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
604                     }
605                     if (shouldBeCurrent && !record.isGuest) {
606                         mLastNonGuestUser = record.info.id;
607                     }
608                     if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) {
609                         // Immediately remove restricted records in case the AsyncTask is too slow.
610                         mUsers.remove(i);
611                         i--;
612                     }
613                 }
614                 notifyAdapters();
615 
616                 // Disconnect from the old secondary user's service
617                 if (mSecondaryUser != UserHandle.USER_NULL) {
618                     context.stopServiceAsUser(mSecondaryUserServiceIntent,
619                             UserHandle.of(mSecondaryUser));
620                     mSecondaryUser = UserHandle.USER_NULL;
621                 }
622                 // Connect to the new secondary user's service (purely to ensure that a persistent
623                 // SystemUI application is created for that user)
624                 if (userInfo != null && userInfo.id != UserHandle.USER_SYSTEM) {
625                     context.startServiceAsUser(mSecondaryUserServiceIntent,
626                             UserHandle.of(userInfo.id));
627                     mSecondaryUser = userInfo.id;
628                 }
629                 unpauseRefreshUsers = true;
630                 if (mGuestUserAutoCreated) {
631                     // Guest user must be scheduled for creation AFTER switching to the target user.
632                     // This avoids lock contention which will produce UX bugs on the keyguard
633                     // (b/193933686).
634                     // TODO(b/191067027): Move guest user recreation to system_server
635                     guaranteeGuestPresent();
636                 }
637             } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
638                 forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
639                         UserHandle.USER_NULL);
640             } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
641                 // Unlocking the system user may require a refresh
642                 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
643                 if (userId != UserHandle.USER_SYSTEM) {
644                     return;
645                 }
646             }
647             refreshUsers(forcePictureLoadForId);
648             if (unpauseRefreshUsers) {
649                 mUnpauseRefreshUsers.run();
650             }
651         }
652     };
653 
654     private final Runnable mUnpauseRefreshUsers = new Runnable() {
655         @Override
656         public void run() {
657             mHandler.removeCallbacks(this);
658             mPauseRefreshUsers = false;
659             refreshUsers(UserHandle.USER_NULL);
660         }
661     };
662 
663     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)664     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
665         pw.println("UserSwitcherController state:");
666         pw.println("  mLastNonGuestUser=" + mLastNonGuestUser);
667         pw.print("  mUsers.size="); pw.println(mUsers.size());
668         for (int i = 0; i < mUsers.size(); i++) {
669             final UserRecord u = mUsers.get(i);
670             pw.print("    "); pw.println(u.toString());
671         }
672         pw.println("mSimpleUserSwitcher=" + mSimpleUserSwitcher);
673         pw.println("mGuestUserAutoCreated=" + mGuestUserAutoCreated);
674     }
675 
676     /** Returns the name of the current user of the phone. */
getCurrentUserName()677     public String getCurrentUserName() {
678         if (mUsers.isEmpty()) return null;
679         UserRecord item = mUsers.get(0);
680         if (item == null || item.info == null) return null;
681         if (item.isGuest) return mContext.getString(
682                 com.android.settingslib.R.string.guest_nickname);
683         return item.info.name;
684     }
685 
onDensityOrFontScaleChanged()686     public void onDensityOrFontScaleChanged() {
687         refreshUsers(UserHandle.USER_ALL);
688     }
689 
690     @VisibleForTesting
addAdapter(WeakReference<BaseUserAdapter> adapter)691     public void addAdapter(WeakReference<BaseUserAdapter> adapter) {
692         mAdapters.add(adapter);
693     }
694 
695     @VisibleForTesting
getUsers()696     public ArrayList<UserRecord> getUsers() {
697         return mUsers;
698     }
699 
700     /**
701      * Removes guest user and switches to target user. The guest must be the current user and its id
702      * must be {@code guestUserId}.
703      *
704      * <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in
705      * the foreground, and immediately switch to it. This is used for wiping the current guest and
706      * replacing it with a new one.
707      *
708      * <p>If {@code targetUserId} is specified, then remove the guest in the background while
709      * switching to {@code targetUserId}.
710      *
711      * <p>If device is configured with {@link
712      * com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a
713      * new one is created in the background. This has no effect if {@code targetUserId} is {@link
714      * UserHandle.USER_NULL}.
715      *
716      * @param guestUserId id of the guest user to remove
717      * @param targetUserId id of the user to switch to after guest is removed. If {@link
718      * UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
719      */
removeGuestUser(@serIdInt int guestUserId, @UserIdInt int targetUserId)720     public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
721         UserInfo currentUser = mUserTracker.getUserInfo();
722         if (currentUser.id != guestUserId) {
723             Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
724                     + " is not current user (" + currentUser.id + ")");
725             return;
726         }
727         if (!currentUser.isGuest()) {
728             Log.w(TAG, "User requesting to start a new session (" + guestUserId + ")"
729                     + " is not a guest");
730             return;
731         }
732 
733         boolean marked = mUserManager.markGuestForDeletion(currentUser.id);
734         if (!marked) {
735             Log.w(TAG, "Couldn't mark the guest for deletion for user " + guestUserId);
736             return;
737         }
738 
739         try {
740             if (targetUserId == UserHandle.USER_NULL) {
741                 // Create a new guest in the foreground, and then immediately switch to it
742                 int newGuestId = createGuest();
743                 if (newGuestId == UserHandle.USER_NULL) {
744                     Log.e(TAG, "Could not create new guest, switching back to system user");
745                     switchToUserId(UserHandle.USER_SYSTEM);
746                     mUserManager.removeUser(currentUser.id);
747                     WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null);
748                     return;
749                 }
750                 switchToUserId(newGuestId);
751                 mUserManager.removeUser(currentUser.id);
752             } else {
753                 if (mGuestUserAutoCreated) {
754                     mGuestIsResetting.set(true);
755                 }
756                 switchToUserId(targetUserId);
757                 mUserManager.removeUser(currentUser.id);
758             }
759         } catch (RemoteException e) {
760             Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead");
761             return;
762         }
763     }
764 
scheduleGuestCreation()765     private void scheduleGuestCreation() {
766         if (!mGuestCreationScheduled.compareAndSet(false, true)) {
767             return;
768         }
769 
770         mBgExecutor.execute(() -> {
771             int newGuestId = createGuest();
772             mGuestCreationScheduled.set(false);
773             mGuestIsResetting.set(false);
774             if (newGuestId == UserHandle.USER_NULL) {
775                 Log.w(TAG, "Could not create new guest while exiting existing guest");
776                 // Refresh users so that we still display "Guest" if
777                 // config_guestUserAutoCreated=true
778                 refreshUsers(UserHandle.USER_NULL);
779             }
780         });
781 
782     }
783 
784     /**
785      * Guarantee guest is present only if the device is provisioned. Otherwise, create a content
786      * observer to wait until the device is provisioned, then schedule the guest creation.
787      */
schedulePostBootGuestCreation()788     public void schedulePostBootGuestCreation() {
789         if (isDeviceAllowedToAddGuest()) {
790             guaranteeGuestPresent();
791         } else {
792             mDeviceProvisionedController.addCallback(mGuaranteeGuestPresentAfterProvisioned);
793         }
794     }
795 
isDeviceAllowedToAddGuest()796     private boolean isDeviceAllowedToAddGuest() {
797         return mDeviceProvisionedController.isDeviceProvisioned()
798                 && !mDevicePolicyManager.isDeviceManaged();
799     }
800 
801     /**
802      * If there is no guest on the device, schedule creation of a new guest user in the background.
803      */
guaranteeGuestPresent()804     private void guaranteeGuestPresent() {
805         if (isDeviceAllowedToAddGuest() && mUserManager.findCurrentGuestUser() == null) {
806             scheduleGuestCreation();
807         }
808     }
809 
810     /**
811      * Creates a guest user and return its multi-user user ID.
812      *
813      * This method does not check if a guest already exists before it makes a call to
814      * {@link UserManager} to create a new one.
815      *
816      * @return The multi-user user ID of the newly created guest user, or
817      * {@link UserHandle.USER_NULL} if the guest couldn't be created.
818      */
createGuest()819     public @UserIdInt int createGuest() {
820         UserInfo guest;
821         try {
822             guest = mUserManager.createGuest(mContext,
823                     mContext.getString(com.android.settingslib.R.string.guest_nickname));
824         } catch (UserManager.UserOperationException e) {
825             Log.e(TAG, "Couldn't create guest user", e);
826             return UserHandle.USER_NULL;
827         }
828         if (guest == null) {
829             Log.e(TAG, "Couldn't create guest, most likely because there already exists one");
830             return UserHandle.USER_NULL;
831         }
832         return guest.id;
833     }
834 
init(NotificationShadeWindowView notificationShadeWindowView)835     public void init(NotificationShadeWindowView notificationShadeWindowView) {
836         mRootView = notificationShadeWindowView;
837     }
838 
839     public static abstract class BaseUserAdapter extends BaseAdapter {
840 
841         final UserSwitcherController mController;
842         private final KeyguardStateController mKeyguardStateController;
843 
BaseUserAdapter(UserSwitcherController controller)844         protected BaseUserAdapter(UserSwitcherController controller) {
845             mController = controller;
846             mKeyguardStateController = controller.mKeyguardStateController;
847             controller.addAdapter(new WeakReference<>(this));
848         }
849 
getUsers()850         protected ArrayList<UserRecord> getUsers() {
851             return mController.getUsers();
852         }
853 
getUserCount()854         public int getUserCount() {
855             return countUsers(false);
856         }
857 
858         @Override
getCount()859         public int getCount() {
860             return countUsers(true);
861         }
862 
countUsers(boolean includeGuest)863         private int countUsers(boolean includeGuest) {
864             boolean keyguardShowing = mKeyguardStateController.isShowing();
865             final int userSize = getUsers().size();
866             int count = 0;
867             for (int i = 0; i < userSize; i++) {
868                 if (getUsers().get(i).isGuest && !includeGuest) {
869                     continue;
870                 }
871                 if (getUsers().get(i).isRestricted && keyguardShowing) {
872                     break;
873                 }
874                 count++;
875             }
876             return count;
877         }
878 
879         @Override
getItem(int position)880         public UserRecord getItem(int position) {
881             return getUsers().get(position);
882         }
883 
884         @Override
getItemId(int position)885         public long getItemId(int position) {
886             return position;
887         }
888 
889         /**
890          * It handles click events on user list items.
891          *
892          * If the user switcher is hosted in a dialog, passing a non-null {@link DialogShower}
893          * will allow animation to and from the parent dialog.
894          *
895          */
onUserListItemClicked(UserRecord record, @Nullable DialogShower dialogShower)896         public void onUserListItemClicked(UserRecord record, @Nullable DialogShower dialogShower) {
897             mController.onUserListItemClicked(record, dialogShower);
898         }
899 
onUserListItemClicked(UserRecord record)900         public void onUserListItemClicked(UserRecord record) {
901             onUserListItemClicked(record, null);
902         }
903 
getName(Context context, UserRecord item)904         public String getName(Context context, UserRecord item) {
905             if (item.isGuest) {
906                 if (item.isCurrent) {
907                     return context.getString(mController.mGuestUserAutoCreated
908                             ? com.android.settingslib.R.string.guest_reset_guest
909                             : com.android.settingslib.R.string.guest_exit_guest);
910                 } else {
911                     if (item.info != null) {
912                         return context.getString(com.android.settingslib.R.string.guest_nickname);
913                     } else {
914                         if (mController.mGuestUserAutoCreated) {
915                             // If mGuestIsResetting=true, we expect the guest user to be created
916                             // shortly, so display a "Resetting guest..." as an indicator that we
917                             // are busy. Otherwise, if mGuestIsResetting=false, we probably failed
918                             // to create a guest at some point. In this case, always show guest
919                             // nickname instead of "Add guest" to make it seem as though the device
920                             // always has a guest ready for use.
921                             return context.getString(
922                                     mController.mGuestIsResetting.get()
923                                             ? com.android.settingslib.R.string.guest_resetting
924                                             : com.android.settingslib.R.string.guest_nickname);
925                         } else {
926                             return context.getString(
927                                     com.android.settingslib.R.string.guest_new_guest);
928                         }
929                     }
930                 }
931             } else if (item.isAddUser) {
932                 return context.getString(R.string.user_add_user);
933             } else {
934                 return item.info.name;
935             }
936         }
937 
getDisabledUserAvatarColorFilter()938         protected static ColorFilter getDisabledUserAvatarColorFilter() {
939             ColorMatrix matrix = new ColorMatrix();
940             matrix.setSaturation(0f);   // 0 - grayscale
941             return new ColorMatrixColorFilter(matrix);
942         }
943 
getIconDrawable(Context context, UserRecord item)944         protected static Drawable getIconDrawable(Context context, UserRecord item) {
945             int iconRes;
946             if (item.isAddUser) {
947                 iconRes = R.drawable.ic_add_circle;
948             } else if (item.isGuest) {
949                 iconRes = R.drawable.ic_avatar_guest_user;
950             } else {
951                 iconRes = R.drawable.ic_avatar_user;
952             }
953 
954             return context.getDrawable(iconRes);
955         }
956 
refresh()957         public void refresh() {
958             mController.refreshUsers(UserHandle.USER_NULL);
959         }
960     }
961 
checkIfAddUserDisallowedByAdminOnly(UserRecord record)962     private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
963         EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
964                 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
965         if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
966                 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
967             record.isDisabledByAdmin = true;
968             record.enforcedAdmin = admin;
969         } else {
970             record.isDisabledByAdmin = false;
971             record.enforcedAdmin = null;
972         }
973     }
974 
shouldUseSimpleUserSwitcher()975     private boolean shouldUseSimpleUserSwitcher() {
976         int defaultSimpleUserSwitcher = mContext.getResources().getBoolean(
977                 com.android.internal.R.bool.config_expandLockScreenUserSwitcher) ? 1 : 0;
978         return Settings.Global.getInt(mContext.getContentResolver(),
979                 SIMPLE_USER_SWITCHER_GLOBAL_SETTING, defaultSimpleUserSwitcher) != 0;
980     }
981 
startActivity(Intent intent)982     public void startActivity(Intent intent) {
983         mActivityStarter.startActivity(intent, true);
984     }
985 
986     public static final class UserRecord {
987         public final UserInfo info;
988         public final Bitmap picture;
989         public final boolean isGuest;
990         public final boolean isCurrent;
991         public final boolean isAddUser;
992         /** If true, the record is only visible to the owner and only when unlocked. */
993         public final boolean isRestricted;
994         public boolean isDisabledByAdmin;
995         public EnforcedAdmin enforcedAdmin;
996         public boolean isSwitchToEnabled;
997 
UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent, boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled)998         public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
999                 boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
1000             this.info = info;
1001             this.picture = picture;
1002             this.isGuest = isGuest;
1003             this.isCurrent = isCurrent;
1004             this.isAddUser = isAddUser;
1005             this.isRestricted = isRestricted;
1006             this.isSwitchToEnabled = isSwitchToEnabled;
1007         }
1008 
copyWithIsCurrent(boolean _isCurrent)1009         public UserRecord copyWithIsCurrent(boolean _isCurrent) {
1010             return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
1011                     isSwitchToEnabled);
1012         }
1013 
resolveId()1014         public int resolveId() {
1015             if (isGuest || info == null) {
1016                 return UserHandle.USER_NULL;
1017             }
1018             return info.id;
1019         }
1020 
toString()1021         public String toString() {
1022             StringBuilder sb = new StringBuilder();
1023             sb.append("UserRecord(");
1024             if (info != null) {
1025                 sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
1026             } else {
1027                 if (isGuest) {
1028                     sb.append("<add guest placeholder>");
1029                 } else if (isAddUser) {
1030                     sb.append("<add user placeholder>");
1031                 }
1032             }
1033             if (isGuest) sb.append(" <isGuest>");
1034             if (isAddUser) sb.append(" <isAddUser>");
1035             if (isCurrent) sb.append(" <isCurrent>");
1036             if (picture != null) sb.append(" <hasPicture>");
1037             if (isRestricted) sb.append(" <isRestricted>");
1038             if (isDisabledByAdmin) {
1039                 sb.append(" <isDisabledByAdmin>");
1040                 sb.append(" enforcedAdmin=").append(enforcedAdmin);
1041             }
1042             if (isSwitchToEnabled) {
1043                 sb.append(" <isSwitchToEnabled>");
1044             }
1045             sb.append(')');
1046             return sb.toString();
1047         }
1048     }
1049 
1050     public static class UserDetailAdapter implements DetailAdapter {
1051         private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
1052 
1053         private final Context mContext;
1054         private final Provider<UserDetailView.Adapter> mUserDetailViewAdapterProvider;
1055 
1056         @Inject
UserDetailAdapter(Context context, Provider<UserDetailView.Adapter> userDetailViewAdapterProvider)1057         UserDetailAdapter(Context context,
1058                 Provider<UserDetailView.Adapter> userDetailViewAdapterProvider) {
1059             mContext = context;
1060             mUserDetailViewAdapterProvider = userDetailViewAdapterProvider;
1061         }
1062 
1063         @Override
getTitle()1064         public CharSequence getTitle() {
1065             return mContext.getString(R.string.quick_settings_user_title);
1066         }
1067 
1068         @Override
createDetailView(Context context, View convertView, ViewGroup parent)1069         public View createDetailView(Context context, View convertView, ViewGroup parent) {
1070             UserDetailView v;
1071             if (!(convertView instanceof UserDetailView)) {
1072                 v = UserDetailView.inflate(context, parent, false);
1073                 v.setAdapter(mUserDetailViewAdapterProvider.get());
1074             } else {
1075                 v = (UserDetailView) convertView;
1076             }
1077             v.refreshAdapter();
1078             return v;
1079         }
1080 
1081         @Override
getSettingsIntent()1082         public Intent getSettingsIntent() {
1083             return USER_SETTINGS_INTENT;
1084         }
1085 
1086         @Override
getSettingsText()1087         public int getSettingsText() {
1088             return R.string.quick_settings_more_user_settings;
1089         }
1090 
1091         @Override
getToggleState()1092         public Boolean getToggleState() {
1093             return null;
1094         }
1095 
1096         @Override
setToggleState(boolean state)1097         public void setToggleState(boolean state) {
1098         }
1099 
1100         @Override
getMetricsCategory()1101         public int getMetricsCategory() {
1102             return MetricsEvent.QS_USERDETAIL;
1103         }
1104 
1105         @Override
openDetailEvent()1106         public UiEventLogger.UiEventEnum openDetailEvent() {
1107             return QSUserSwitcherEvent.QS_USER_DETAIL_OPEN;
1108         }
1109 
1110         @Override
closeDetailEvent()1111         public UiEventLogger.UiEventEnum closeDetailEvent() {
1112             return QSUserSwitcherEvent.QS_USER_DETAIL_CLOSE;
1113         }
1114 
1115         @Override
moreSettingsEvent()1116         public UiEventLogger.UiEventEnum moreSettingsEvent() {
1117             return QSUserSwitcherEvent.QS_USER_MORE_SETTINGS;
1118         }
1119     };
1120 
1121     private final KeyguardStateController.Callback mCallback =
1122             new KeyguardStateController.Callback() {
1123                 @Override
1124                 public void onKeyguardShowingChanged() {
1125 
1126                     // When Keyguard is going away, we don't need to update our items immediately
1127                     // which
1128                     // helps making the transition faster.
1129                     if (!mKeyguardStateController.isShowing()) {
1130                         mHandler.post(UserSwitcherController.this::notifyAdapters);
1131                     } else {
1132                         notifyAdapters();
1133                     }
1134                 }
1135             };
1136 
1137     private final DeviceProvisionedController.DeviceProvisionedListener
1138             mGuaranteeGuestPresentAfterProvisioned =
1139             new DeviceProvisionedController.DeviceProvisionedListener() {
1140                 @Override
1141                 public void onDeviceProvisionedChanged() {
1142                     if (isDeviceAllowedToAddGuest()) {
1143                         mBgExecutor.execute(
1144                                 () -> mDeviceProvisionedController.removeCallback(
1145                                         mGuaranteeGuestPresentAfterProvisioned));
1146                         guaranteeGuestPresent();
1147                     }
1148                 }
1149             };
1150 
1151 
1152     private final class ExitGuestDialog extends SystemUIDialog implements
1153             DialogInterface.OnClickListener {
1154 
1155         private final int mGuestId;
1156         private final int mTargetId;
1157 
ExitGuestDialog(Context context, int guestId, int targetId)1158         public ExitGuestDialog(Context context, int guestId, int targetId) {
1159             super(context);
1160             setTitle(mGuestUserAutoCreated
1161                     ? com.android.settingslib.R.string.guest_reset_guest_dialog_title
1162                     : R.string.guest_exit_guest_dialog_title);
1163             setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
1164             setButton(DialogInterface.BUTTON_NEUTRAL,
1165                     context.getString(android.R.string.cancel), this);
1166             setButton(DialogInterface.BUTTON_POSITIVE,
1167                     context.getString(mGuestUserAutoCreated
1168                             ? com.android.settingslib.R.string.guest_reset_guest_confirm_button
1169                             : R.string.guest_exit_guest_dialog_remove), this);
1170             SystemUIDialog.setWindowOnTop(this);
1171             setCanceledOnTouchOutside(false);
1172             mGuestId = guestId;
1173             mTargetId = targetId;
1174         }
1175 
1176         @Override
onClick(DialogInterface dialog, int which)1177         public void onClick(DialogInterface dialog, int which) {
1178             int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY
1179                     : FalsingManager.HIGH_PENALTY;
1180             if (mFalsingManager.isFalseTap(penalty)) {
1181                 return;
1182             }
1183             if (which == BUTTON_NEUTRAL) {
1184                 cancel();
1185             } else {
1186                 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE);
1187                 mDialogLaunchAnimator.dismissStack(this);
1188                 removeGuestUser(mGuestId, mTargetId);
1189             }
1190         }
1191     }
1192 
1193     @VisibleForTesting
1194     final class AddUserDialog extends SystemUIDialog implements
1195             DialogInterface.OnClickListener {
1196 
AddUserDialog(Context context)1197         public AddUserDialog(Context context) {
1198             super(context);
1199             setTitle(R.string.user_add_user_title);
1200             setMessage(context.getString(R.string.user_add_user_message_short));
1201             setButton(DialogInterface.BUTTON_NEUTRAL,
1202                     context.getString(android.R.string.cancel), this);
1203             setButton(DialogInterface.BUTTON_POSITIVE,
1204                     context.getString(android.R.string.ok), this);
1205             SystemUIDialog.setWindowOnTop(this);
1206         }
1207 
1208         @Override
onClick(DialogInterface dialog, int which)1209         public void onClick(DialogInterface dialog, int which) {
1210             int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY
1211                     : FalsingManager.MODERATE_PENALTY;
1212             if (mFalsingManager.isFalseTap(penalty)) {
1213                 return;
1214             }
1215             if (which == BUTTON_NEUTRAL) {
1216                 cancel();
1217             } else {
1218                 mDialogLaunchAnimator.dismissStack(this);
1219                 if (ActivityManager.isUserAMonkey()) {
1220                     return;
1221                 }
1222                 Intent intent = CreateUserActivity.createIntentForStart(getContext());
1223 
1224                 // There are some differences between ActivityStarter and ActivityTaskManager in
1225                 // terms of how they start an activity. ActivityStarter hides the notification bar
1226                 // before starting the activity to make sure nothing is in front of the new
1227                 // activity. ActivityStarter also tries to unlock the device if it's locked.
1228                 // When locked with PIN/pattern/password then it shows the prompt, if there are no
1229                 // security steps then it dismisses the keyguard and then starts the activity.
1230                 // ActivityTaskManager doesn't hide the notification bar or unlocks the device, but
1231                 // it can start an activity on top of the locked screen.
1232                 if (!mKeyguardStateController.isUnlocked()
1233                         && !mKeyguardStateController.canDismissLockScreen()) {
1234                     // Device is locked and can't be unlocked without a PIN/pattern/password so we
1235                     // need to use ActivityTaskManager to start the activity on top of the locked
1236                     // screen.
1237                     try {
1238                         mActivityTaskManager.startActivity(null,
1239                                 mContext.getBasePackageName(), mContext.getAttributionTag(), intent,
1240                                 intent.resolveTypeIfNeeded(mContext.getContentResolver()), null,
1241                                 null, 0, 0, null, null);
1242                     } catch (RemoteException e) {
1243                         e.printStackTrace();
1244                         Log.e(TAG, "Couldn't start create user activity", e);
1245                     }
1246                 } else {
1247                     mActivityStarter.startActivity(intent, true);
1248                 }
1249             }
1250         }
1251     }
1252 }
1253