100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos/*
200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * Copyright (C) 2014 The Android Open Source Project
300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos *
400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * Licensed under the Apache License, Version 2.0 (the "License");
500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * you may not use this file except in compliance with the License.
600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * You may obtain a copy of the License at
700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos *
800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos *      http://www.apache.org/licenses/LICENSE-2.0
900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos *
1000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * Unless required by applicable law or agreed to in writing, software
1100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * distributed under the License is distributed on an "AS IS" BASIS,
1200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * See the License for the specific language governing permissions and
1400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * limitations under the License
1500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos */
1600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
1700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roospackage com.android.systemui.statusbar.policy;
1800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
19ec015d5cb510d26d4e951feb240be8025f477ff5Xiaohui Chenimport static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
20ec015d5cb510d26d4e951feb240be8025f477ff5Xiaohui Chen
21334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monkimport android.R.attr;
2200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.app.ActivityManager;
235005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport android.app.Dialog;
24f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolovimport android.app.Notification;
25f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolovimport android.app.NotificationManager;
26f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolovimport android.app.PendingIntent;
2700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.BroadcastReceiver;
2800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.Context;
295005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport android.content.DialogInterface;
3000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.Intent;
3100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.IntentFilter;
3200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.pm.UserInfo;
332daf62ce400fe58c7f0495dda432ba568a75f579Jason Monkimport android.database.ContentObserver;
3400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.graphics.Bitmap;
35334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monkimport android.graphics.PorterDuff.Mode;
36ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roosimport android.graphics.drawable.Drawable;
3700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.AsyncTask;
382daf62ce400fe58c7f0495dda432ba568a75f579Jason Monkimport android.os.Handler;
3900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.RemoteException;
40e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roosimport android.os.UserHandle;
4100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.UserManager;
422daf62ce400fe58c7f0495dda432ba568a75f579Jason Monkimport android.provider.Settings;
43523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolovimport android.telephony.PhoneStateListener;
44523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolovimport android.telephony.TelephonyManager;
4500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.util.Log;
46e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roosimport android.util.SparseArray;
4788b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roosimport android.util.SparseBooleanArray;
4800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.view.View;
4900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.view.ViewGroup;
5000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.widget.BaseAdapter;
5100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
52383db5ebcc3a4a615faf249bf4f126f42e80b82eTamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
538852905b0b3837e326127c6dfef6f699124ce715Jason Monkimport com.android.internal.annotations.VisibleForTesting;
545e6c0ffd3e91cf0c5872de3e2d99e225ad1468f4Chris Wrenimport com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
5564d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghinaimport com.android.internal.util.UserIcons;
561c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shankaimport com.android.settingslib.RestrictedLockUtils;
57334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monkimport com.android.settingslib.Utils;
589c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monkimport com.android.systemui.Dependency;
5964d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghinaimport com.android.systemui.GuestResumeSessionReceiver;
6064d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghinaimport com.android.systemui.R;
61e25c18da7d2cc3e02620dadfcb976521821bc9d8Adrian Roosimport com.android.systemui.SystemUI;
623c2c34bb039e92d68f466b7d194cbbe8241d8d60Winsonimport com.android.systemui.SystemUISecondaryUserService;
63e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monkimport com.android.systemui.plugins.qs.DetailAdapter;
6464d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghinaimport com.android.systemui.qs.tiles.UserDetailView;
65ec34da8f6f31c5ee1e543c0c7999a067487e0ce9Jason Monkimport com.android.systemui.plugins.ActivityStarter;
6664d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghinaimport com.android.systemui.statusbar.phone.SystemUIDialog;
678e032e15e6b1b6a2f44fd3d5063ee83f45d71189Dan Sandlerimport com.android.systemui.util.NotificationChannels;
6864d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghina
6900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.io.FileDescriptor;
7000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.io.PrintWriter;
7100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.lang.ref.WeakReference;
7200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.util.ArrayList;
7300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.util.List;
7400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
7500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos/**
7600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * Keeps a list of all users on the device for user switching.
7700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos */
7800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roospublic class UserSwitcherController {
7900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
8000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private static final String TAG = "UserSwitcherController";
815005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private static final boolean DEBUG = false;
822daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk    private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
832daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk            "lockscreenSimpleUserSwitcher";
84f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov    private static final String ACTION_REMOVE_GUEST = "com.android.systemui.REMOVE_GUEST";
85860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen    private static final String ACTION_LOGOUT_USER = "com.android.systemui.LOGOUT_USER";
8688b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
8700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
88d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani    private static final String TAG_REMOVE_GUEST = "remove_guest";
89860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen    private static final String TAG_LOGOUT_USER = "logout_user";
90860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen
91d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
92d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani
9313a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected final Context mContext;
9413a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected final UserManager mUserManager;
9500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
965005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
975005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            = new GuestResumeSessionReceiver();
98ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    private final KeyguardMonitor mKeyguardMonitor;
9913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected final Handler mHandler;
1001c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka    private final ActivityStarter mActivityStarter;
10100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
10200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private ArrayList<UserRecord> mUsers = new ArrayList<>();
1035005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private Dialog mExitGuestDialog;
1040c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos    private Dialog mAddUserDialog;
1057cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen    private int mLastNonGuestUser = UserHandle.USER_SYSTEM;
10637c76807a047193338e3af317fb39373d69c7561Evan Rosky    private boolean mResumeUserOnGuestLogout = true;
107ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    private boolean mSimpleUserSwitcher;
108ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    private boolean mAddUsersWhenLocked;
10988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    private boolean mPauseRefreshUsers;
1103c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson    private int mSecondaryUser = UserHandle.USER_NULL;
1113c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson    private Intent mSecondaryUserServiceIntent;
11288b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
11300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
11488b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
1151c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            Handler handler, ActivityStarter activityStarter) {
11600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        mContext = context;
1175005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        mGuestResumeSessionReceiver.register(context);
118ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        mKeyguardMonitor = keyguardMonitor;
11988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        mHandler = handler;
1201c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        mActivityStarter = activityStarter;
12100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        mUserManager = UserManager.get(context);
12200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        IntentFilter filter = new IntentFilter();
12300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_ADDED);
12400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_REMOVED);
12500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
12600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_SWITCHED);
127ad2e4bf9f36cf612db6c397feca8effb125ee541Amith Yamasani        filter.addAction(Intent.ACTION_USER_STOPPED);
12807140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov        filter.addAction(Intent.ACTION_USER_UNLOCKED);
1297cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen        mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
130e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                null /* permission */, null /* scheduler */);
1312daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk
1323c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson        mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class);
1333c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson
134d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani        filter = new IntentFilter();
135d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani        filter.addAction(ACTION_REMOVE_GUEST);
136860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen        filter.addAction(ACTION_LOGOUT_USER);
1375891a346abbde5bfe95a52633d05533406cc6a2eAmith Yamasani        mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
138d81f8270bec71ec9a569c8308c42cacd7aba0d23Amith Yamasani                PERMISSION_SELF, null /* scheduler */);
139ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos
1402daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk        mContext.getContentResolver().registerContentObserver(
1412daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true,
142ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                mSettingsObserver);
143ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        mContext.getContentResolver().registerContentObserver(
144ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                Settings.Global.getUriFor(Settings.Global.ADD_USERS_WHEN_LOCKED), true,
145ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                mSettingsObserver);
14607140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov        mContext.getContentResolver().registerContentObserver(
14707140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                Settings.Global.getUriFor(
14807140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                        Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED),
14907140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                true, mSettingsObserver);
150ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        // Fetch initial values.
151ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        mSettingsObserver.onChange(false);
152ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos
153ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        keyguardMonitor.addCallback(mCallback);
154523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov        listenForCallState();
1552daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk
156e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        refreshUsers(UserHandle.USER_NULL);
15700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
15800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
159e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    /**
160e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * Refreshes users from UserManager.
161e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     *
162e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * The pictures are only loaded if they have not been loaded yet.
163e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     *
164e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
165e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     */
16695ab7849444125387dc88088bb5197ee463d8c17Amith Yamasani    @SuppressWarnings("unchecked")
167e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    private void refreshUsers(int forcePictureLoadForId) {
16888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")");
16988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        if (forcePictureLoadForId != UserHandle.USER_NULL) {
17088b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            mForcePictureLoadForUserId.put(forcePictureLoadForId, true);
17188b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        }
17288b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos
17388b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        if (mPauseRefreshUsers) {
17488b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            return;
17588b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        }
176c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos
177d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos        boolean forceAllUsers = mForcePictureLoadForUserId.get(UserHandle.USER_ALL);
178c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos        SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
179c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos        final int N = mUsers.size();
180c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos        for (int i = 0; i < N; i++) {
181c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos            UserRecord r = mUsers.get(i);
182d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos            if (r == null || r.picture == null || r.info == null || forceAllUsers
183d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos                    || mForcePictureLoadForUserId.get(r.info.id)) {
184c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos                continue;
185e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
186c5db390f5b5c6c685267dd22cf3b2926f54fba35Adrian Roos            bitmaps.put(r.info.id, r.picture);
187e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        }
18888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        mForcePictureLoadForUserId.clear();
189e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
190ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        final boolean addUsersWhenLocked = mAddUsersWhenLocked;
191e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
192e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            @SuppressWarnings("unchecked")
19300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            @Override
194e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
195e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                final SparseArray<Bitmap> bitmaps = params[0];
19600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                List<UserInfo> infos = mUserManager.getUsers(true);
19700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                if (infos == null) {
19800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    return null;
19900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
20000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                ArrayList<UserRecord> records = new ArrayList<>(infos.size());
20100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                int currentId = ActivityManager.getCurrentUser();
202523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                boolean canSwitchUsers = mUserManager.canSwitchUsers();
2037cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                UserInfo currentUserInfo = null;
20400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                UserRecord guestRecord = null;
20500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
20600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                for (UserInfo info : infos) {
20700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    boolean isCurrent = currentId == info.id;
2087cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                    if (isCurrent) {
2097cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                        currentUserInfo = info;
2107cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                    }
211523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                    boolean switchToEnabled = canSwitchUsers || isCurrent;
2121ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                    if (info.isEnabled()) {
2131ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                        if (info.isGuest()) {
214523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                            // Tapping guest icon triggers remove and a user switch therefore
215523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                            // the icon shouldn't be enabled even if the user is current
2161ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                            guestRecord = new UserRecord(info, null /* picture */,
2171ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                    true /* isGuest */, isCurrent, false /* isAddUser */,
218523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                                    false /* isRestricted */, canSwitchUsers);
2191ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                        } else if (info.supportsSwitchToByUser()) {
2201ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                            Bitmap picture = bitmaps.get(info.id);
2211ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                            if (picture == null) {
2221ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                picture = mUserManager.getUserIcon(info.id);
2231ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova
2241ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                if (picture != null) {
225aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky                                    int avatarSize = mContext.getResources()
226aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky                                            .getDimensionPixelSize(R.dimen.max_avatar_size);
227aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky                                    picture = Bitmap.createScaledBitmap(
228aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky                                            picture, avatarSize, avatarSize, true);
2291ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                }
230cba0faadbe1c8cf7c6b264b761d747f7381a2f93Adrian Roos                            }
2311ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                            int index = isCurrent ? 0 : records.size();
2321ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                            records.add(index, new UserRecord(info, picture, false /* isGuest */,
2331ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                    isCurrent, false /* isAddUser */, false /* isRestricted */,
2341ddda4793c26fd249590fd3549cf060ecb7c157bLenka Trochtova                                    switchToEnabled));
2354d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                        }
23600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    }
23700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
23800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
239a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
240a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                                UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
2417cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                boolean currentUserCanCreateUsers = currentUserInfo != null
2427cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                        && (currentUserInfo.isAdmin()
243a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                                || currentUserInfo.id == UserHandle.USER_SYSTEM)
244a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                        && systemCanCreateUsers;
245a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
246a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
247ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        && guestRecord == null;
248a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
24995ab7849444125387dc88088bb5197ee463d8c17Amith Yamasani                        && mUserManager.canAddMoreUsers();
250ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                boolean createIsRestricted = !addUsersWhenLocked;
251ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos
2522daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                if (!mSimpleUserSwitcher) {
2532daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                    if (guestRecord == null) {
254ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        if (canCreateGuest) {
2551c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka                            guestRecord = new UserRecord(null /* info */, null /* picture */,
256ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                                    true /* isGuest */, false /* isCurrent */,
257523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                                    false /* isAddUser */, createIsRestricted, canSwitchUsers);
258a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                            checkIfAddUserDisallowedByAdminOnly(guestRecord);
2591c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka                            records.add(guestRecord);
260ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        }
2612daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                    } else {
262bed6e3bedc8845e8f9cd59ad436d140b0875cb6bAdrian Roos                        int index = guestRecord.isCurrent ? 0 : records.size();
263bed6e3bedc8845e8f9cd59ad436d140b0875cb6bAdrian Roos                        records.add(index, guestRecord);
2642daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                    }
26500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
26600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
267092be7de024b8b1a050ad247a016febc795546afJason Monk                if (!mSimpleUserSwitcher && canCreateUser) {
2681c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka                    UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
269ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                            false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
270523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                            createIsRestricted, canSwitchUsers);
271a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka                    checkIfAddUserDisallowedByAdminOnly(addUserRecord);
2721c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka                    records.add(addUserRecord);
273ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                }
274ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos
27500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                return records;
27600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
27700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
27800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            @Override
27900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            protected void onPostExecute(ArrayList<UserRecord> userRecords) {
28000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                if (userRecords != null) {
28100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    mUsers = userRecords;
28200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    notifyAdapters();
28300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
28400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
285ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        }.execute((SparseArray) bitmaps);
28600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
28700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
28888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    private void pauseRefreshUsers() {
28988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        if (!mPauseRefreshUsers) {
29088b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS);
29188b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            mPauseRefreshUsers = true;
29288b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        }
29388b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    }
29488b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos
29500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private void notifyAdapters() {
29600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        for (int i = mAdapters.size() - 1; i >= 0; i--) {
29700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            BaseUserAdapter adapter = mAdapters.get(i).get();
29800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (adapter != null) {
29900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                adapter.notifyDataSetChanged();
30000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            } else {
30100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                mAdapters.remove(i);
30200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
30300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
30400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
30500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
3062daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk    public boolean isSimpleUserSwitcher() {
3072daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk        return mSimpleUserSwitcher;
3082daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk    }
3092daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk
310cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia    public boolean useFullscreenUserSwitcher() {
311cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        // Use adb to override:
312cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        // adb shell settings put system enable_fullscreen_user_switcher 0  # Turn it off.
313cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
314cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        // Restart SystemUI or adb reboot.
315cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        final int DEFAULT = -1;
316cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        final int overrideUseFullscreenUserSwitcher =
317cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia                Settings.System.getInt(mContext.getContentResolver(),
318cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia                        "enable_fullscreen_user_switcher", DEFAULT);
319cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        if (overrideUseFullscreenUserSwitcher != DEFAULT) {
320cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia            return overrideUseFullscreenUserSwitcher != 0;
321cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        }
322cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        // Otherwise default to the build setting.
32340f9dabaa880eaff54099a3763224b241a6668e6Xiyuan Xia        return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
324cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia    }
325cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia
32637c76807a047193338e3af317fb39373d69c7561Evan Rosky    public void setResumeUserOnGuestLogout(boolean resume) {
32737c76807a047193338e3af317fb39373d69c7561Evan Rosky        mResumeUserOnGuestLogout = resume;
32837c76807a047193338e3af317fb39373d69c7561Evan Rosky    }
32937c76807a047193338e3af317fb39373d69c7561Evan Rosky
3301b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia    public void logoutCurrentUser() {
3311b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia        int currentUser = ActivityManager.getCurrentUser();
3321b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia        if (currentUser != UserHandle.USER_SYSTEM) {
333b5690bc3086af1d1f064a080c728090de24d6f96Fyodor Kupolov            pauseRefreshUsers();
334b5690bc3086af1d1f064a080c728090de24d6f96Fyodor Kupolov            ActivityManager.logoutCurrentUser();
3351b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia        }
3361b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia    }
3371b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia
338cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia    public void removeUserId(int userId) {
339cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        if (userId == UserHandle.USER_SYSTEM) {
340cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia            Log.w(TAG, "User " + userId + " could not removed.");
341cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia            return;
342cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        }
343cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        if (ActivityManager.getCurrentUser() == userId) {
344cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia            switchToUserId(UserHandle.USER_SYSTEM);
345cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        }
346cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        if (mUserManager.removeUser(userId)) {
347cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia            refreshUsers(UserHandle.USER_NULL);
348cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia        }
349cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia    }
350cc3a74f6ef13ca9a783845e7a04ca6561035c98bXiyuan Xia
35100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public void switchTo(UserRecord record) {
35200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        int id;
35300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        if (record.isGuest && record.info == null) {
35400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            // No guest user. Create one.
355f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos            UserInfo guest = mUserManager.createGuest(
356f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                    mContext, mContext.getString(R.string.guest_nickname));
357f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos            if (guest == null) {
358f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                // Couldn't create guest, most likely because there already exists one, we just
359f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                // haven't reloaded the user list yet.
360f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                return;
361f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos            }
362f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos            id = guest.id;
363ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        } else if (record.isAddUser) {
3640c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            showAddUserDialog();
3650c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            return;
36600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        } else {
36700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            id = record.info.id;
36800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
36900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
37013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        int currUserId = ActivityManager.getCurrentUser();
37113a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        if (currUserId == id) {
372e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (record.isGuest) {
3735005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                showExitGuestDialog(id);
374e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
37500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return;
37600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
37700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
37813a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        if (UserManager.isGuestUserEphemeral()) {
37913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            // If switching from guest, we want to bring up the guest exit dialog instead of switching
38013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            UserInfo currUserInfo = mUserManager.getUserInfo(currUserId);
38113a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            if (currUserInfo != null && currUserInfo.isGuest()) {
38213a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                showExitGuestDialog(currUserId, record.resolveId());
38313a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                return;
38413a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            }
38513a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        }
38613a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky
387e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        switchToUserId(id);
388e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    }
389e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
390caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov    public void switchTo(int userId) {
391caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov        final int count = mUsers.size();
392caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov        for (int i = 0; i < count; ++i) {
393caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov            UserRecord record = mUsers.get(i);
394caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov            if (record.info != null && record.info.id == userId) {
395caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov                switchTo(record);
396caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov                return;
397caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov            }
398caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov        }
399caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov
400caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov        Log.e(TAG, "Couldn't switch to user, id=" + userId);
401caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov    }
402caab2666bd8dbf1e499c309a62f4dff0056d2948Fyodor Kupolov
4038ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi    public int getSwitchableUserCount() {
4048ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi        int count = 0;
4058ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi        final int N = mUsers.size();
4068ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi        for (int i = 0; i < N; ++i) {
4078ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi            UserRecord record = mUsers.get(i);
4088ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi            if (record.info != null && record.info.supportsSwitchTo()) {
4098ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi                count++;
4108ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi            }
4118ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi        }
4128ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi        return count;
4138ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi    }
4148ba446c9bad94e91cf83c579261298552d51d249Daniel Nishi
41513a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected void switchToUserId(int id) {
41600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        try {
41788b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            pauseRefreshUsers();
418dc589ac82b5fe2063f4cfd94c8ae26d43d5420a0Sudheer Shanka            ActivityManager.getService().switchUser(id);
41900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        } catch (RemoteException e) {
42000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            Log.e(TAG, "Couldn't switch user.", e);
42100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
42200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
42300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
4245005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private void showExitGuestDialog(int id) {
42513a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        int newId = UserHandle.USER_SYSTEM;
42613a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        if (mResumeUserOnGuestLogout && mLastNonGuestUser != UserHandle.USER_SYSTEM) {
42713a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
42813a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            if (info != null && info.isEnabled() && info.supportsSwitchToByUser()) {
42913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                newId = info.id;
43013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            }
43113a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        }
43213a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        showExitGuestDialog(id, newId);
43313a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    }
43413a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky
43513a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected void showExitGuestDialog(int id, int targetId) {
4365005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
4375005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            mExitGuestDialog.cancel();
4385005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
43913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        mExitGuestDialog = new ExitGuestDialog(mContext, id, targetId);
4405005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        mExitGuestDialog.show();
4415005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    }
4425005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
44392c91412ba099f5b5d17a7e28123629a1f7410c8Muyuan Li    public void showAddUserDialog() {
4440c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
4450c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            mAddUserDialog.cancel();
4460c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        }
4470c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        mAddUserDialog = new AddUserDialog(mContext);
4480c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        mAddUserDialog.show();
4490c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos    }
4500c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos
45113a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky    protected void exitGuest(int id, int targetId) {
45213a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        switchToUserId(targetId);
453e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        mUserManager.removeUser(id);
454e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    }
455e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
456523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov    private void listenForCallState() {
457705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk        TelephonyManager.from(mContext).listen(mPhoneStateListener,
458705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk                PhoneStateListener.LISTEN_CALL_STATE);
459523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov    }
460523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov
461705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk    private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
462705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk        private int mCallState;
463705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk
464705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk        @Override
465705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk        public void onCallStateChanged(int state, String incomingNumber) {
466705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            if (mCallState == state) return;
467705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            if (DEBUG) Log.v(TAG, "Call state changed: " + state);
468705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            mCallState = state;
469705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            int currentUserId = ActivityManager.getCurrentUser();
470705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            UserInfo userInfo = mUserManager.getUserInfo(currentUserId);
471705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            if (userInfo != null && userInfo.isGuest()) {
472705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk                showGuestNotification(currentUserId);
473705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            }
474705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk            refreshUsers(UserHandle.USER_NULL);
475705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk        }
476705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk    };
477705a4bc62341d70a9b75b28f68c64efc88321438Jason Monk
47800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
47900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
48000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void onReceive(Context context, Intent intent) {
4815005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            if (DEBUG) {
4825005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                Log.v(TAG, "Broadcast: a=" + intent.getAction()
4835005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                       + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
4845005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            }
48588b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos
48688b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            boolean unpauseRefreshUsers = false;
48788b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            int forcePictureLoadForId = UserHandle.USER_NULL;
48888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos
489f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov            if (ACTION_REMOVE_GUEST.equals(intent.getAction())) {
490f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                int currentUser = ActivityManager.getCurrentUser();
491f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                UserInfo userInfo = mUserManager.getUserInfo(currentUser);
492f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                if (userInfo != null && userInfo.isGuest()) {
493f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                    showExitGuestDialog(currentUser);
494f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                }
495f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov                return;
49680996bbf40ff192117c391074ed2f9b2cde4e69aAdrian Roos            } else if (ACTION_LOGOUT_USER.equals(intent.getAction())) {
4971b30f79cffbe9e0c2b974fa3ee48001edcdd6c05Xiyuan Xia                logoutCurrentUser();
49888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
4995005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
5005005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    mExitGuestDialog.cancel();
5015005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    mExitGuestDialog = null;
5025005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                }
5035005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
50400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5057cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                final UserInfo userInfo = mUserManager.getUserInfo(currentId);
50600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                final int N = mUsers.size();
50700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                for (int i = 0; i < N; i++) {
50800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    UserRecord record = mUsers.get(i);
509e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    if (record.info == null) continue;
51000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    boolean shouldBeCurrent = record.info.id == currentId;
51100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    if (record.isCurrent != shouldBeCurrent) {
51200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                        mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
51300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    }
51470441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                    if (shouldBeCurrent && !record.isGuest) {
51570441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                        mLastNonGuestUser = record.info.id;
51670441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                    }
5177cb69df507f5f7956c52a2868a0d6e89aec6dde2Xiaohui Chen                    if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) {
518ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        // Immediately remove restricted records in case the AsyncTask is too slow.
519ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        mUsers.remove(i);
520ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                        i--;
521ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    }
52200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
52300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                notifyAdapters();
524860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen
5253c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                // Disconnect from the old secondary user's service
5263c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                if (mSecondaryUser != UserHandle.USER_NULL) {
5273c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                    context.stopServiceAsUser(mSecondaryUserServiceIntent,
5283c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                            UserHandle.of(mSecondaryUser));
5293c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                    mSecondaryUser = UserHandle.USER_NULL;
5303c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                }
5313c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                // Connect to the new secondary user's service (purely to ensure that a persistent
5323c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                // SystemUI application is created for that user)
533ec015d5cb510d26d4e951feb240be8025f477ff5Xiaohui Chen                if (userInfo != null && userInfo.id != UserHandle.USER_SYSTEM) {
5343c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                    context.startServiceAsUser(mSecondaryUserServiceIntent,
5353c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                            UserHandle.of(userInfo.id));
5363c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                    mSecondaryUser = userInfo.id;
5373c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson                }
5383c2c34bb039e92d68f466b7d194cbbe8241d8d60Winson
539860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen                if (UserManager.isSplitSystemUser() && userInfo != null && !userInfo.isGuest()
540860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen                        && userInfo.id != UserHandle.USER_SYSTEM) {
541860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen                    showLogoutNotification(currentId);
542860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen                }
543ce161861c3507c91c25b2491abac1e7611d14c5cFyodor Kupolov                if (userInfo != null && userInfo.isGuest()) {
544ce161861c3507c91c25b2491abac1e7611d14c5cFyodor Kupolov                    showGuestNotification(currentId);
545ce161861c3507c91c25b2491abac1e7611d14c5cFyodor Kupolov                }
54688b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos                unpauseRefreshUsers = true;
54788b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
548e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
549e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        UserHandle.USER_NULL);
55007140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov            } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
55107140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                // Unlocking the system user may require a refresh
55207140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
55307140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                if (userId != UserHandle.USER_SYSTEM) {
55407140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                    return;
55507140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                }
556e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
557e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            refreshUsers(forcePictureLoadForId);
55888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            if (unpauseRefreshUsers) {
55988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos                mUnpauseRefreshUsers.run();
56088b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            }
56100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
562f4d6ad26636760163083ae84c40d5b19cb6650f6Fyodor Kupolov
563860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen        private void showLogoutNotification(int userId) {
564860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen            PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
565860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen                    0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
5661dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch            Notification.Builder builder =
5671dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                    new Notification.Builder(mContext, NotificationChannels.GENERAL)
5681dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setVisibility(Notification.VISIBILITY_SECRET)
5691dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setSmallIcon(R.drawable.ic_person)
5701dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setContentTitle(mContext.getString(
5711dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                    R.string.user_logout_notification_title))
5721dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setContentText(mContext.getString(
5731dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                    R.string.user_logout_notification_text))
5741dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setContentIntent(logoutPI)
5751dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setOngoing(true)
5761dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .setShowWhen(false)
5771dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                            .addAction(R.drawable.ic_delete,
5781dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                    mContext.getString(R.string.user_logout_notification_action),
5791dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                    logoutPI);
580e25c18da7d2cc3e02620dadfcb976521821bc9d8Adrian Roos            SystemUI.overrideNotificationAppName(mContext, builder);
5815e6c0ffd3e91cf0c5872de3e2d99e225ad1468f4Chris Wren            NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER,
5825e6c0ffd3e91cf0c5872de3e2d99e225ad1468f4Chris Wren                    SystemMessage.NOTE_LOGOUT_USER, builder.build(), new UserHandle(userId));
583860397f6521249f1e2733e65ccebe0c0e781b82aXiaohui Chen        }
58400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    };
58500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
586523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov    private void showGuestNotification(int guestUserId) {
587523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov        boolean canSwitchUsers = mUserManager.canSwitchUsers();
588523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov        // Disable 'Remove guest' action if cannot switch users right now
589523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov        PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
590523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov                0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
591523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov
5921dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch        Notification.Builder builder =
5931dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                new Notification.Builder(mContext, NotificationChannels.GENERAL)
5941dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setVisibility(Notification.VISIBILITY_SECRET)
5951dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setSmallIcon(R.drawable.ic_person)
5961dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setContentTitle(mContext.getString(R.string.guest_notification_title))
5971dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setContentText(mContext.getString(R.string.guest_notification_text))
5981dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setContentIntent(removeGuestPI)
5991dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .setShowWhen(false)
6001dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                        .addAction(R.drawable.ic_delete,
6011dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                mContext.getString(R.string.guest_notification_remove_action),
6021dc93bc407540561ebba1cc007073ab9c71d7a4eGeoffrey Pitsch                                removeGuestPI);
603e25c18da7d2cc3e02620dadfcb976521821bc9d8Adrian Roos        SystemUI.overrideNotificationAppName(mContext, builder);
6045e6c0ffd3e91cf0c5872de3e2d99e225ad1468f4Chris Wren        NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST,
6055e6c0ffd3e91cf0c5872de3e2d99e225ad1468f4Chris Wren                SystemMessage.NOTE_REMOVE_GUEST, builder.build(), new UserHandle(guestUserId));
606523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov    }
607523c404612c634f6901205fee4f4cae594f62982Fyodor Kupolov
60888b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    private final Runnable mUnpauseRefreshUsers = new Runnable() {
60988b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        @Override
61088b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        public void run() {
61188b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            mHandler.removeCallbacks(this);
61288b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            mPauseRefreshUsers = false;
61388b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos            refreshUsers(UserHandle.USER_NULL);
61488b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos        }
61588b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos    };
61688b1193ea2880683a6a3fdf9a5a397370a166680Adrian Roos
617ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
6182daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk        public void onChange(boolean selfChange) {
6192daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk            mSimpleUserSwitcher = Settings.Global.getInt(mContext.getContentResolver(),
6202daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk                    SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
621ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
622ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
6232daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk            refreshUsers(UserHandle.USER_NULL);
6242daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk        };
6252daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk    };
6262daf62ce400fe58c7f0495dda432ba568a75f579Jason Monk
62700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
62800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        pw.println("UserSwitcherController state:");
62970441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        pw.println("  mLastNonGuestUser=" + mLastNonGuestUser);
63000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        pw.print("  mUsers.size="); pw.println(mUsers.size());
63100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        for (int i = 0; i < mUsers.size(); i++) {
63200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            final UserRecord u = mUsers.get(i);
63300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            pw.print("    "); pw.println(u.toString());
63400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
63500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
63600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
63757cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos    public String getCurrentUserName(Context context) {
63857cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos        if (mUsers.isEmpty()) return null;
63957cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos        UserRecord item = mUsers.get(0);
64057cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos        if (item == null || item.info == null) return null;
64157cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos        if (item.isGuest) return context.getString(R.string.guest_nickname);
64257cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos        return item.info.name;
64357cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos    }
64457cf5702e0634b8cb25daa8f2f73292428ec4e08Adrian Roos
645d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos    public void onDensityOrFontScaleChanged() {
646d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos        refreshUsers(UserHandle.USER_ALL);
647d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos    }
648d390b893eafae634844d7b8b84efaa7baa199119Adrian Roos
6498852905b0b3837e326127c6dfef6f699124ce715Jason Monk    @VisibleForTesting
6508852905b0b3837e326127c6dfef6f699124ce715Jason Monk    public void addAdapter(WeakReference<BaseUserAdapter> adapter) {
6518852905b0b3837e326127c6dfef6f699124ce715Jason Monk        mAdapters.add(adapter);
6528852905b0b3837e326127c6dfef6f699124ce715Jason Monk    }
6538852905b0b3837e326127c6dfef6f699124ce715Jason Monk
6548852905b0b3837e326127c6dfef6f699124ce715Jason Monk    @VisibleForTesting
6558852905b0b3837e326127c6dfef6f699124ce715Jason Monk    public ArrayList<UserRecord> getUsers() {
6568852905b0b3837e326127c6dfef6f699124ce715Jason Monk        return mUsers;
6578852905b0b3837e326127c6dfef6f699124ce715Jason Monk    }
6588852905b0b3837e326127c6dfef6f699124ce715Jason Monk
65900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public static abstract class BaseUserAdapter extends BaseAdapter {
66000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
66100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        final UserSwitcherController mController;
6629c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk        private final KeyguardMonitor mKeyguardMonitor;
66300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
66400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        protected BaseUserAdapter(UserSwitcherController controller) {
66500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            mController = controller;
6669c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk            mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
6678852905b0b3837e326127c6dfef6f699124ce715Jason Monk            controller.addAdapter(new WeakReference<>(this));
66800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
66900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
670e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk        public int getUserCount() {
671e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
672e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                    && mKeyguardMonitor.isSecure()
673e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                    && !mKeyguardMonitor.canSkipBouncer();
674e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            if (!secureKeyguardShowing) {
675e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                return mController.getUsers().size();
676e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            }
677e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            // The lock screen is secure and showing. Filter out restricted records.
678e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            final int N = mController.getUsers().size();
679e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            int count = 0;
680e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            for (int i = 0; i < N; i++) {
681e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                if (mController.getUsers().get(i).isGuest) continue;
682e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                if (mController.getUsers().get(i).isRestricted) {
683e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                    break;
684e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                } else {
685e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                    count++;
686e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk                }
687e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            }
688e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk            return count;
689e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk        }
690e5b770e47d44a40d412c7d42010b2cf67920d9e3Jason Monk
69100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
69200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public int getCount() {
6939c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk            boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
6949c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk                    && mKeyguardMonitor.isSecure()
6959c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk                    && !mKeyguardMonitor.canSkipBouncer();
696ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (!secureKeyguardShowing) {
6978852905b0b3837e326127c6dfef6f699124ce715Jason Monk                return mController.getUsers().size();
698ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            }
699ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            // The lock screen is secure and showing. Filter out restricted records.
7008852905b0b3837e326127c6dfef6f699124ce715Jason Monk            final int N = mController.getUsers().size();
701ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            int count = 0;
702ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            for (int i = 0; i < N; i++) {
7038852905b0b3837e326127c6dfef6f699124ce715Jason Monk                if (mController.getUsers().get(i).isRestricted) {
704ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    break;
705ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                } else {
706ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    count++;
707ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                }
708ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            }
709ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            return count;
71000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
71100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
71200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
71300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public UserRecord getItem(int position) {
7148852905b0b3837e326127c6dfef6f699124ce715Jason Monk            return mController.getUsers().get(position);
71500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
71600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
71700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
71800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public long getItemId(int position) {
719e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            return position;
72000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
72100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
72200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void switchTo(UserRecord record) {
72300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            mController.switchTo(record);
72400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
725e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
726e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        public String getName(Context context, UserRecord item) {
727e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (item.isGuest) {
728e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                if (item.isCurrent) {
729e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    return context.getString(R.string.guest_exit_guest);
730e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                } else {
731e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    return context.getString(
732e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                            item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
733e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                }
734ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            } else if (item.isAddUser) {
735ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                return context.getString(R.string.user_add_user);
736e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            } else {
737e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                return item.info.name;
738e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
739e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        }
740723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos
741ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        public Drawable getDrawable(Context context, UserRecord item) {
742ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (item.isAddUser) {
743ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                return context.getDrawable(R.drawable.ic_add_circle_qs);
744ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            }
745334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk            Drawable icon = UserIcons.getDefaultUserIcon(item.resolveId(), /* light= */ false);
746334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk            if (item.isGuest) {
747334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk                icon.setColorFilter(Utils.getColorAttr(context, android.R.attr.colorForeground),
748334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk                        Mode.SRC_IN);
749334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk            }
750334b04b4d68e0126d57beba3171e6bcac88ede11Jason Monk            return icon;
751ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        }
752844c92b444dca7f5ef4d0943fb14e2cbeee49701Adrian Roos
753844c92b444dca7f5ef4d0943fb14e2cbeee49701Adrian Roos        public void refresh() {
754844c92b444dca7f5ef4d0943fb14e2cbeee49701Adrian Roos            mController.refreshUsers(UserHandle.USER_NULL);
755844c92b444dca7f5ef4d0943fb14e2cbeee49701Adrian Roos        }
75600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
75700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
758a8fbbb30eae03b9ed7a3e6ea78da13480a53b73dSudheer Shanka    private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
759ad143c09dfbae2f4bb26be8b2a9425edf0562b46Sudheer Shanka        EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
760ad143c09dfbae2f4bb26be8b2a9425edf0562b46Sudheer Shanka                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
761ad143c09dfbae2f4bb26be8b2a9425edf0562b46Sudheer Shanka        if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
762ad143c09dfbae2f4bb26be8b2a9425edf0562b46Sudheer Shanka                UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
7631c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            record.isDisabledByAdmin = true;
764ad143c09dfbae2f4bb26be8b2a9425edf0562b46Sudheer Shanka            record.enforcedAdmin = admin;
7651c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        } else {
7661c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            record.isDisabledByAdmin = false;
7671c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            record.enforcedAdmin = null;
7681c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        }
7691c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka    }
7701c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka
7711c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka    public void startActivity(Intent intent) {
7721c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        mActivityStarter.startActivity(intent, true);
7731c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka    }
7741c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka
77500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public static final class UserRecord {
77600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final UserInfo info;
77700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final Bitmap picture;
77800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final boolean isGuest;
77900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final boolean isCurrent;
780ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        public final boolean isAddUser;
781ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        /** If true, the record is only visible to the owner and only when unlocked. */
782ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        public final boolean isRestricted;
7831c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        public boolean isDisabledByAdmin;
7841c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka        public EnforcedAdmin enforcedAdmin;
78507140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov        public boolean isSwitchToEnabled;
78600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
787ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
78807140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled) {
78900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.info = info;
79000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.picture = picture;
79100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.isGuest = isGuest;
79200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.isCurrent = isCurrent;
793ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            this.isAddUser = isAddUser;
794ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            this.isRestricted = isRestricted;
79507140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov            this.isSwitchToEnabled = isSwitchToEnabled;
79600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
79700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
79800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public UserRecord copyWithIsCurrent(boolean _isCurrent) {
79907140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov            return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
80007140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                    isSwitchToEnabled);
80100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
80200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
803aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky        public int resolveId() {
804aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky            if (isGuest || info == null) {
805aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky                return UserHandle.USER_NULL;
806aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky            }
807aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky            return info.id;
808aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky        }
809aa7f51fe8c6e54485f0b5037c17777b4695d19e0Evan Rosky
81000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public String toString() {
81100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            StringBuilder sb = new StringBuilder();
81200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            sb.append("UserRecord(");
81300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (info != null) {
81407140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
81500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            } else {
816ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                if (isGuest) {
817ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    sb.append("<add guest placeholder>");
818ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                } else if (isAddUser) {
819ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                    sb.append("<add user placeholder>");
820ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos                }
82100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
822ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (isGuest) sb.append(" <isGuest>");
823ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (isAddUser) sb.append(" <isAddUser>");
824ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (isCurrent) sb.append(" <isCurrent>");
825ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (picture != null) sb.append(" <hasPicture>");
826ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos            if (isRestricted) sb.append(" <isRestricted>");
8271c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            if (isDisabledByAdmin) {
8281c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka                sb.append(" <isDisabledByAdmin>");
82907140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                sb.append(" enforcedAdmin=").append(enforcedAdmin);
83007140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov            }
83107140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov            if (isSwitchToEnabled) {
83207140f7ffd56bf9d4946eba4e48b21a748125659Fyodor Kupolov                sb.append(" <isSwitchToEnabled>");
8331c7cda8bbfb848961536a4adbf2c81c5ffddae16Sudheer Shanka            }
83400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            sb.append(')');
83500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return sb.toString();
83600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
83700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
83800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
83946767b77c004a3541c614f8e21d6a871dd148e54Jason Monk    public final DetailAdapter userDetailAdapter = new DetailAdapter() {
84076c67aa361f65dfb2f5e03d06cc1ccebce9cecd9Jason Monk        private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
84100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
84200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
843c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk        public CharSequence getTitle() {
844c06fbb12984a3d3e4c80ab9f819841acae5b0133Jason Monk            return mContext.getString(R.string.quick_settings_user_title);
84500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
84600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
84700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
84800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public View createDetailView(Context context, View convertView, ViewGroup parent) {
8491940892d891c1d2538f51608b6618af646ab7481Adrian Roos            UserDetailView v;
85000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (!(convertView instanceof UserDetailView)) {
8511940892d891c1d2538f51608b6618af646ab7481Adrian Roos                v = UserDetailView.inflate(context, parent, false);
85200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                v.createAndSetAdapter(UserSwitcherController.this);
8531940892d891c1d2538f51608b6618af646ab7481Adrian Roos            } else {
8541940892d891c1d2538f51608b6618af646ab7481Adrian Roos                v = (UserDetailView) convertView;
85500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
856844c92b444dca7f5ef4d0943fb14e2cbeee49701Adrian Roos            v.refreshAdapter();
85700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return v;
85800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
85900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
86000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
86100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public Intent getSettingsIntent() {
86200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return USER_SETTINGS_INTENT;
86300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
86400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
86500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
86600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public Boolean getToggleState() {
86700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return null;
86800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
86900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
87000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
87100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void setToggleState(boolean state) {
87200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
873457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren
874457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren        @Override
875457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren        public int getMetricsCategory() {
876f6e9228b8a97603d3ceb8f0d61e8d87cf19bd21fChris Wren            return MetricsEvent.QS_USERDETAIL;
877457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren        }
87800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    };
8795005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
880ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
881ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        @Override
882aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk        public void onKeyguardShowingChanged() {
883e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi
884e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi            // When Keyguard is going away, we don't need to update our items immediately which
885e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi            // helps making the transition faster.
886e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi            if (!mKeyguardMonitor.isShowing()) {
887e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi                mHandler.post(UserSwitcherController.this::notifyAdapters);
888e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi            } else {
889e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi                notifyAdapters();
890e549a8d62108c7c7dabedbf4e77b9a653781723bJorim Jaggi            }
891ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos        }
892ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos    };
893ccdff62159b41ab130a8f90d30edb9b9542d8c72Adrian Roos
8945005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private final class ExitGuestDialog extends SystemUIDialog implements
8955005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            DialogInterface.OnClickListener {
8965005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
8975005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        private final int mGuestId;
89813a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        private final int mTargetId;
8995005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
90013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky        public ExitGuestDialog(Context context, int guestId, int targetId) {
9015005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            super(context);
9025005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setTitle(R.string.guest_exit_guest_dialog_title);
9035005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
9045005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setButton(DialogInterface.BUTTON_NEGATIVE,
905e5b274ac612400a7bc9f258d4ef3c366cfa1bc11Amith Yamasani                    context.getString(android.R.string.cancel), this);
9065005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setButton(DialogInterface.BUTTON_POSITIVE,
907e5b274ac612400a7bc9f258d4ef3c366cfa1bc11Amith Yamasani                    context.getString(R.string.guest_exit_guest_dialog_remove), this);
9085005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setCanceledOnTouchOutside(false);
9095005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            mGuestId = guestId;
91013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            mTargetId = targetId;
9115005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
9125005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
9135005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        @Override
9145005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        public void onClick(DialogInterface dialog, int which) {
9155005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            if (which == BUTTON_NEGATIVE) {
9165005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                cancel();
9175005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            } else {
9185005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                dismiss();
91913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                exitGuest(mGuestId, mTargetId);
9205005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            }
9215005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
9225005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    }
9230c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos
9240c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos    private final class AddUserDialog extends SystemUIDialog implements
9250c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            DialogInterface.OnClickListener {
9260c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos
9270c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        public AddUserDialog(Context context) {
9280c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            super(context);
9290c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            setTitle(R.string.user_add_user_title);
9300c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            setMessage(context.getString(R.string.user_add_user_message_short));
9310c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            setButton(DialogInterface.BUTTON_NEGATIVE,
9320c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos                    context.getString(android.R.string.cancel), this);
9330c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            setButton(DialogInterface.BUTTON_POSITIVE,
9340c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos                    context.getString(android.R.string.ok), this);
9350c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        }
9360c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos
9370c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        @Override
9380c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        public void onClick(DialogInterface dialog, int which) {
9390c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            if (which == BUTTON_NEGATIVE) {
9400c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos                cancel();
9410c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            } else {
9420c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos                dismiss();
943ccbeb61ac21527839deb115199cbe98fa2b73c05Guang Zhu                if (ActivityManager.isUserAMonkey()) {
944ccbeb61ac21527839deb115199cbe98fa2b73c05Guang Zhu                    return;
945ccbeb61ac21527839deb115199cbe98fa2b73c05Guang Zhu                }
946cfe64c8afa9f30d8874c72440c3992e79fdb60c9Xiaohui Chen                UserInfo user = mUserManager.createUser(
947f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                        mContext.getString(R.string.user_new_user_name), 0 /* flags */);
948f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                if (user == null) {
949f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                    // Couldn't create user, most likely because there are too many, but we haven't
950f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                    // been able to reload the list yet.
951f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                    return;
952f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                }
953f99727cb878f9709f6c0263c0283257decbaebadAdrian Roos                int id = user.id;
95464d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghina                Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
95564d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghina                        id, /* light= */ false));
95664d4dca63f65e4c7d4a829c85ff6670bdd34e2ebAlexandra Gherghina                mUserManager.setUserIcon(id, icon);
9570c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos                switchToUserId(id);
9580c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos            }
9590c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos        }
9600c6763a19f32f73f8a940aaee7abecb2a04d1889Adrian Roos    }
96100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos}
962