UserSwitcherController.java revision 00a0b1f397557790cf9ab55fe06e72a96ebc5353
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.systemui.statusbar.policy; 18 19import com.android.systemui.R; 20import com.android.systemui.qs.QSTile; 21import com.android.systemui.qs.tiles.UserDetailView; 22 23import android.app.ActivityManager; 24import android.app.ActivityManagerNative; 25import android.content.BroadcastReceiver; 26import android.content.Context; 27import android.content.Intent; 28import android.content.IntentFilter; 29import android.content.pm.UserInfo; 30import android.graphics.Bitmap; 31import android.os.AsyncTask; 32import android.os.RemoteException; 33import android.os.UserManager; 34import android.util.Log; 35import android.view.View; 36import android.view.ViewGroup; 37import android.view.WindowManagerGlobal; 38import android.widget.BaseAdapter; 39 40import java.io.FileDescriptor; 41import java.io.PrintWriter; 42import java.lang.ref.WeakReference; 43import java.util.ArrayList; 44import java.util.List; 45 46/** 47 * Keeps a list of all users on the device for user switching. 48 */ 49public class UserSwitcherController { 50 51 private static final String TAG = "UserSwitcherController"; 52 53 private final Context mContext; 54 private final UserManager mUserManager; 55 private final ArrayList<WeakReference<BaseUserAdapter>> mAdapters = new ArrayList<>(); 56 57 private ArrayList<UserRecord> mUsers = new ArrayList<>(); 58 59 public UserSwitcherController(Context context) { 60 mContext = context; 61 mUserManager = UserManager.get(context); 62 IntentFilter filter = new IntentFilter(); 63 filter.addAction(Intent.ACTION_USER_ADDED); 64 filter.addAction(Intent.ACTION_USER_REMOVED); 65 filter.addAction(Intent.ACTION_USER_INFO_CHANGED); 66 filter.addAction(Intent.ACTION_USER_SWITCHED); 67 mContext.registerReceiver(mReceiver, filter); 68 refreshUsers(); 69 } 70 71 private void refreshUsers() { 72 new AsyncTask<Void, Void, ArrayList<UserRecord>>() { 73 74 @Override 75 protected ArrayList<UserRecord> doInBackground(Void... params) { 76 List<UserInfo> infos = mUserManager.getUsers(true); 77 if (infos == null) { 78 return null; 79 } 80 ArrayList<UserRecord> records = new ArrayList<>(infos.size()); 81 int currentId = ActivityManager.getCurrentUser(); 82 UserRecord guestRecord = null; 83 84 for (UserInfo info : infos) { 85 boolean isCurrent = currentId == info.id; 86 if (info.isGuest()) { 87 guestRecord = new UserRecord(info, null /* picture */, 88 true /* isGuest */, isCurrent); 89 } else if (!info.isManagedProfile()) { 90 records.add(new UserRecord(info, mUserManager.getUserIcon(info.id), 91 false /* isGuest */, isCurrent)); 92 } 93 } 94 95 if (guestRecord == null) { 96 records.add(new UserRecord(null /* info */, null /* picture */, 97 true /* isGuest */, false /* isCurrent */)); 98 } else { 99 records.add(guestRecord); 100 } 101 102 return records; 103 } 104 105 @Override 106 protected void onPostExecute(ArrayList<UserRecord> userRecords) { 107 if (userRecords != null) { 108 mUsers = userRecords; 109 notifyAdapters(); 110 } 111 } 112 }.execute((Void[])null); 113 } 114 115 private void notifyAdapters() { 116 for (int i = mAdapters.size() - 1; i >= 0; i--) { 117 BaseUserAdapter adapter = mAdapters.get(i).get(); 118 if (adapter != null) { 119 adapter.notifyDataSetChanged(); 120 } else { 121 mAdapters.remove(i); 122 } 123 } 124 } 125 126 public void switchTo(UserRecord record) { 127 int id; 128 if (record.isGuest && record.info == null) { 129 // No guest user. Create one. 130 id = mUserManager.createGuest(mContext, 131 mContext.getResources().getString(R.string.guest_nickname)).id; 132 } else { 133 id = record.info.id; 134 } 135 136 if (ActivityManager.getCurrentUser() == id) { 137 return; 138 } 139 140 try { 141 WindowManagerGlobal.getWindowManagerService().lockNow(null); 142 ActivityManagerNative.getDefault().switchUser(id); 143 } catch (RemoteException e) { 144 Log.e(TAG, "Couldn't switch user.", e); 145 } 146 } 147 148 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 149 @Override 150 public void onReceive(Context context, Intent intent) { 151 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 152 final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 153 final int N = mUsers.size(); 154 for (int i = 0; i < N; i++) { 155 UserRecord record = mUsers.get(i); 156 boolean shouldBeCurrent = record.info.id == currentId; 157 if (record.isCurrent != shouldBeCurrent) { 158 mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent)); 159 } 160 } 161 notifyAdapters(); 162 } else { 163 refreshUsers(); 164 } 165 } 166 }; 167 168 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 169 pw.println("UserSwitcherController state:"); 170 pw.print(" mUsers.size="); pw.println(mUsers.size()); 171 for (int i = 0; i < mUsers.size(); i++) { 172 final UserRecord u = mUsers.get(i); 173 pw.print(" "); pw.println(u.toString()); 174 } 175 } 176 177 public static abstract class BaseUserAdapter extends BaseAdapter { 178 179 final UserSwitcherController mController; 180 181 protected BaseUserAdapter(UserSwitcherController controller) { 182 mController = controller; 183 controller.mAdapters.add(new WeakReference<>(this)); 184 } 185 186 @Override 187 public int getCount() { 188 return mController.mUsers.size(); 189 } 190 191 @Override 192 public UserRecord getItem(int position) { 193 return mController.mUsers.get(position); 194 } 195 196 @Override 197 public long getItemId(int position) { 198 return mController.mUsers.get(position).info.id; 199 } 200 201 public void switchTo(UserRecord record) { 202 mController.switchTo(record); 203 } 204 } 205 206 public static final class UserRecord { 207 public final UserInfo info; 208 public final Bitmap picture; 209 public final boolean isGuest; 210 public final boolean isCurrent; 211 212 public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent) { 213 this.info = info; 214 this.picture = picture; 215 this.isGuest = isGuest; 216 this.isCurrent = isCurrent; 217 } 218 219 public UserRecord copyWithIsCurrent(boolean _isCurrent) { 220 return new UserRecord(info, picture, isGuest, _isCurrent); 221 } 222 223 public String toString() { 224 StringBuilder sb = new StringBuilder(); 225 sb.append("UserRecord("); 226 if (info != null) { 227 sb.append("name=\"" + info.name + "\" id=" + info.id); 228 } else { 229 sb.append("<add guest placeholder>"); 230 } 231 if (isGuest) { 232 sb.append(" <isGuest>"); 233 } 234 if (isCurrent) { 235 sb.append(" <isCurrent>"); 236 } 237 if (picture != null) { 238 sb.append(" <hasPicture>"); 239 } 240 sb.append(')'); 241 return sb.toString(); 242 } 243 } 244 245 public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() { 246 private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS"); 247 248 @Override 249 public int getTitle() { 250 return R.string.quick_settings_user_title; 251 } 252 253 @Override 254 public View createDetailView(Context context, View convertView, ViewGroup parent) { 255 if (!(convertView instanceof UserDetailView)) { 256 convertView = UserDetailView.inflate(context, parent, false); 257 } 258 UserDetailView v = (UserDetailView) convertView; 259 if (v.getAdapter() == null) { 260 v.createAndSetAdapter(UserSwitcherController.this); 261 } 262 return v; 263 } 264 265 @Override 266 public Intent getSettingsIntent() { 267 return USER_SETTINGS_INTENT; 268 } 269 270 @Override 271 public Boolean getToggleState() { 272 return null; 273 } 274 275 @Override 276 public void setToggleState(boolean state) { 277 } 278 }; 279} 280