UserSwitcherController.java revision 723632ea1ae30b33e9c2055194a4464f00c48c61
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
194d75c079f35d85b687d8349e5e2940447d01198eDan Sandlerimport com.android.systemui.BitmapHelper;
205005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport com.android.systemui.GuestResumeSessionReceiver;
2100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport com.android.systemui.R;
2200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport com.android.systemui.qs.QSTile;
2300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport com.android.systemui.qs.tiles.UserDetailView;
245005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport com.android.systemui.statusbar.phone.SystemUIDialog;
2500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
2600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.app.ActivityManager;
2700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.app.ActivityManagerNative;
285005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport android.app.Dialog;
2900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.BroadcastReceiver;
3000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.Context;
315005244f10442e75c1f48973fdddce5facf3f360Adrian Roosimport android.content.DialogInterface;
3200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.Intent;
3300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.IntentFilter;
3400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.content.pm.UserInfo;
3500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.graphics.Bitmap;
3600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.AsyncTask;
3700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.RemoteException;
38e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roosimport android.os.UserHandle;
3900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.os.UserManager;
4000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.util.Log;
41e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roosimport android.util.SparseArray;
4200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.view.View;
4300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.view.ViewGroup;
4400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.view.WindowManagerGlobal;
4500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport android.widget.BaseAdapter;
4600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
4700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.io.FileDescriptor;
4800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.io.PrintWriter;
4900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.lang.ref.WeakReference;
5000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.util.ArrayList;
5100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roosimport java.util.List;
5200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
5300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos/**
5400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos * Keeps a list of all users on the device for user switching.
5500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos */
5600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roospublic class UserSwitcherController {
5700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
5800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private static final String TAG = "UserSwitcherController";
595005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private static final boolean DEBUG = false;
6000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
6100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private final Context mContext;
6200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private final UserManager mUserManager;
6300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>();
645005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private final GuestResumeSessionReceiver mGuestResumeSessionReceiver
655005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            = new GuestResumeSessionReceiver();
6600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
6700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private ArrayList<UserRecord> mUsers = new ArrayList<>();
685005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private Dialog mExitGuestDialog;
6970441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos    private int mLastNonGuestUser = UserHandle.USER_OWNER;
7000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
7100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public UserSwitcherController(Context context) {
7200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        mContext = context;
735005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        mGuestResumeSessionReceiver.register(context);
7400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        mUserManager = UserManager.get(context);
7500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        IntentFilter filter = new IntentFilter();
7600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_ADDED);
7700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_REMOVED);
7800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
7900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        filter.addAction(Intent.ACTION_USER_SWITCHED);
80e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        filter.addAction(Intent.ACTION_USER_STOPPING);
81e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
82e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                null /* permission */, null /* scheduler */);
83e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        refreshUsers(UserHandle.USER_NULL);
8400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
8500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
86e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    /**
87e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * Refreshes users from UserManager.
88e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     *
89e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * The pictures are only loaded if they have not been loaded yet.
90e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     *
91e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
92e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos     */
93e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    private void refreshUsers(int forcePictureLoadForId) {
9400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
95e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
96e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        final int N = mUsers.size();
97e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        for (int i = 0; i < N; i++) {
98e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            UserRecord r = mUsers.get(i);
99e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (r == null || r.info == null
100e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    || r.info.id == forcePictureLoadForId || r.picture == null) {
101e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                continue;
102e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
103e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            bitmaps.put(r.info.id, r.picture);
104e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        }
105e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
106e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() {
107e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            @SuppressWarnings("unchecked")
10800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            @Override
109e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            protected ArrayList<UserRecord> doInBackground(SparseArray<Bitmap>... params) {
110e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                final SparseArray<Bitmap> bitmaps = params[0];
11100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                List<UserInfo> infos = mUserManager.getUsers(true);
11200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                if (infos == null) {
11300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    return null;
11400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
11500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                ArrayList<UserRecord> records = new ArrayList<>(infos.size());
11600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                int currentId = ActivityManager.getCurrentUser();
11700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                UserRecord guestRecord = null;
1184d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                int avatarSize = mContext.getResources()
1194d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                        .getDimensionPixelSize(R.dimen.max_avatar_size);
12000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
12100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                for (UserInfo info : infos) {
12200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    boolean isCurrent = currentId == info.id;
12300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    if (info.isGuest()) {
12400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                        guestRecord = new UserRecord(info, null /* picture */,
12500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                                true /* isGuest */, isCurrent);
126723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos                    } else if (info.supportsSwitchTo()) {
127e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        Bitmap picture = bitmaps.get(info.id);
128e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        if (picture == null) {
129e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                            picture = mUserManager.getUserIcon(info.id);
130e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        }
1314d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                        if (picture != null) {
1324d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                            picture = BitmapHelper.createCircularClip(
1334d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                                    picture, avatarSize, avatarSize);
1344d75c079f35d85b687d8349e5e2940447d01198eDan Sandler                        }
135e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent));
13600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    }
13700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
13800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
13900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                if (guestRecord == null) {
14000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    records.add(new UserRecord(null /* info */, null /* picture */,
14100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                            true /* isGuest */, false /* isCurrent */));
14200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                } else {
14300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    records.add(guestRecord);
14400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
14500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
14600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                return records;
14700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
14800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
14900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            @Override
15000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            protected void onPostExecute(ArrayList<UserRecord> userRecords) {
15100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                if (userRecords != null) {
15200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    mUsers = userRecords;
15300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    notifyAdapters();
15400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
15500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
156e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        }.execute((SparseArray)bitmaps);
15700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
15800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
15900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private void notifyAdapters() {
16000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        for (int i = mAdapters.size() - 1; i >= 0; i--) {
16100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            BaseUserAdapter adapter = mAdapters.get(i).get();
16200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (adapter != null) {
16300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                adapter.notifyDataSetChanged();
16400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            } else {
16500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                mAdapters.remove(i);
16600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
16700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
16800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
16900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
17000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public void switchTo(UserRecord record) {
17100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        int id;
17200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        if (record.isGuest && record.info == null) {
17300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            // No guest user. Create one.
17400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            id = mUserManager.createGuest(mContext,
17500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    mContext.getResources().getString(R.string.guest_nickname)).id;
17600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        } else {
17700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            id = record.info.id;
17800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
17900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
18000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        if (ActivityManager.getCurrentUser() == id) {
181e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (record.isGuest) {
1825005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                showExitGuestDialog(id);
183e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
18400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return;
18500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
18600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
187e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        switchToUserId(id);
188e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    }
189e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
190e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    private void switchToUserId(int id) {
19100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        try {
19200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            WindowManagerGlobal.getWindowManagerService().lockNow(null);
19300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            ActivityManagerNative.getDefault().switchUser(id);
19400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        } catch (RemoteException e) {
19500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            Log.e(TAG, "Couldn't switch user.", e);
19600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
19700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
19800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
1995005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private void showExitGuestDialog(int id) {
2005005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
2015005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            mExitGuestDialog.cancel();
2025005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
2035005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        mExitGuestDialog = new ExitGuestDialog(mContext, id);
2045005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        mExitGuestDialog.show();
2055005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    }
2065005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
207e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    private void exitGuest(int id) {
20870441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        int newId = UserHandle.USER_OWNER;
20970441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        if (mLastNonGuestUser != UserHandle.USER_OWNER) {
21070441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos            UserInfo info = mUserManager.getUserInfo(mLastNonGuestUser);
21170441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos            if (info != null && info.isEnabled() && info.supportsSwitchTo()) {
21270441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                newId = info.id;
21370441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos            }
21470441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        }
21570441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        switchToUserId(newId);
216e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        mUserManager.removeUser(id);
217e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos    }
218e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
21900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
22000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
22100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void onReceive(Context context, Intent intent) {
2225005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            if (DEBUG) {
2235005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                Log.v(TAG, "Broadcast: a=" + intent.getAction()
2245005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                       + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
2255005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            }
22600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
2275005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
2285005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    mExitGuestDialog.cancel();
2295005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    mExitGuestDialog = null;
2305005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                }
2315005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
23200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
23300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                final int N = mUsers.size();
23400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                for (int i = 0; i < N; i++) {
23500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    UserRecord record = mUsers.get(i);
236e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    if (record.info == null) continue;
23700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    boolean shouldBeCurrent = record.info.id == currentId;
23800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    if (record.isCurrent != shouldBeCurrent) {
23900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                        mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent));
24000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                    }
24170441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                    if (shouldBeCurrent && !record.isGuest) {
24270441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                        mLastNonGuestUser = record.info.id;
24370441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos                    }
24400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                }
24500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                notifyAdapters();
24600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
247e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            int forcePictureLoadForId = UserHandle.USER_NULL;
248e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) {
249e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
250e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                        UserHandle.USER_NULL);
251e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
252e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            refreshUsers(forcePictureLoadForId);
25300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
25400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    };
25500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
25600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
25700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        pw.println("UserSwitcherController state:");
25870441467f4dc232cd8e6142f0afc117787dc979bAdrian Roos        pw.println("  mLastNonGuestUser=" + mLastNonGuestUser);
25900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        pw.print("  mUsers.size="); pw.println(mUsers.size());
26000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        for (int i = 0; i < mUsers.size(); i++) {
26100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            final UserRecord u = mUsers.get(i);
26200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            pw.print("    "); pw.println(u.toString());
26300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
26400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
26500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
26600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public static abstract class BaseUserAdapter extends BaseAdapter {
26700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
26800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        final UserSwitcherController mController;
26900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
27000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        protected BaseUserAdapter(UserSwitcherController controller) {
27100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            mController = controller;
27200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            controller.mAdapters.add(new WeakReference<>(this));
27300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
27400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
27500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
27600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public int getCount() {
27700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return mController.mUsers.size();
27800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
27900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
28000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
28100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public UserRecord getItem(int position) {
28200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return mController.mUsers.get(position);
28300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
28400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
28500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
28600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public long getItemId(int position) {
287e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            return position;
28800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
28900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
29000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void switchTo(UserRecord record) {
29100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            mController.switchTo(record);
29200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
293e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos
294e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        public String getName(Context context, UserRecord item) {
295e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            if (item.isGuest) {
296e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                if (item.isCurrent) {
297e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    return context.getString(R.string.guest_exit_guest);
298e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                } else {
299e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                    return context.getString(
300e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                            item.info == null ? R.string.guest_new_guest : R.string.guest_nickname);
301e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                }
302e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            } else {
303e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos                return item.info.name;
304e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos            }
305e9c7d431da85b5bc03ecaa964d7a491b01466a99Adrian Roos        }
306723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos
307723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos        public int getSwitchableUsers() {
308723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            int result = 0;
309723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            ArrayList<UserRecord> users = mController.mUsers;
310723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            int N = users.size();
311723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            for (int i = 0; i < N; i++) {
312723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos                if (users.get(i).info != null) {
313723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos                    result++;
314723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos                }
315723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            }
316723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos            return result;
317723632ea1ae30b33e9c2055194a4464f00c48c61Adrian Roos        }
31800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
31900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
32000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public static final class UserRecord {
32100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final UserInfo info;
32200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final Bitmap picture;
32300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final boolean isGuest;
32400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public final boolean isCurrent;
32500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
32600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent) {
32700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.info = info;
32800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.picture = picture;
32900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.isGuest = isGuest;
33000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            this.isCurrent = isCurrent;
33100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
33200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
33300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public UserRecord copyWithIsCurrent(boolean _isCurrent) {
33400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return new UserRecord(info, picture, isGuest, _isCurrent);
33500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
33600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
33700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public String toString() {
33800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            StringBuilder sb = new StringBuilder();
33900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            sb.append("UserRecord(");
34000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (info != null) {
34100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                sb.append("name=\"" + info.name + "\" id=" + info.id);
34200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            } else {
34300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                sb.append("<add guest placeholder>");
34400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
34500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (isGuest) {
34600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                sb.append(" <isGuest>");
34700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
34800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (isCurrent) {
34900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                sb.append(" <isCurrent>");
35000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
35100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (picture != null) {
35200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                sb.append(" <hasPicture>");
35300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
35400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            sb.append(')');
35500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return sb.toString();
35600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
35700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    }
35800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
35900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
36000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
36100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
36200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
36300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public int getTitle() {
36400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return R.string.quick_settings_user_title;
36500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
36600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
36700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
36800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public View createDetailView(Context context, View convertView, ViewGroup parent) {
36900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (!(convertView instanceof UserDetailView)) {
37000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                convertView = UserDetailView.inflate(context, parent, false);
37100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
37200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            UserDetailView v = (UserDetailView) convertView;
37300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            if (v.getAdapter() == null) {
37400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos                v.createAndSetAdapter(UserSwitcherController.this);
37500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            }
37600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return v;
37700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
37800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
37900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
38000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public Intent getSettingsIntent() {
38100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return USER_SETTINGS_INTENT;
38200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
38300a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
38400a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
38500a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public Boolean getToggleState() {
38600a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos            return null;
38700a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
38800a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos
38900a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        @Override
39000a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        public void setToggleState(boolean state) {
39100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos        }
39200a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos    };
3935005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
3945005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    private final class ExitGuestDialog extends SystemUIDialog implements
3955005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            DialogInterface.OnClickListener {
3965005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
3975005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        private final int mGuestId;
3985005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
3995005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        public ExitGuestDialog(Context context, int guestId) {
4005005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            super(context);
4015005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setTitle(R.string.guest_exit_guest_dialog_title);
4025005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setMessage(context.getString(R.string.guest_exit_guest_dialog_message));
4035005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setButton(DialogInterface.BUTTON_NEGATIVE,
4045005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    context.getString(android.R.string.no), this);
4055005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setButton(DialogInterface.BUTTON_POSITIVE,
4065005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                    context.getString(android.R.string.yes), this);
4075005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            setCanceledOnTouchOutside(false);
4085005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            mGuestId = guestId;
4095005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
4105005244f10442e75c1f48973fdddce5facf3f360Adrian Roos
4115005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        @Override
4125005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        public void onClick(DialogInterface dialog, int which) {
4135005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            if (which == BUTTON_NEGATIVE) {
4145005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                cancel();
4155005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            } else {
4165005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                dismiss();
4175005244f10442e75c1f48973fdddce5facf3f360Adrian Roos                exitGuest(mGuestId);
4185005244f10442e75c1f48973fdddce5facf3f360Adrian Roos            }
4195005244f10442e75c1f48973fdddce5facf3f360Adrian Roos        }
4205005244f10442e75c1f48973fdddce5facf3f360Adrian Roos    }
42100a0b1f397557790cf9ab55fe06e72a96ebc5353Adrian Roos}
422