1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.systemui.statusbar.policy; 18 19 import android.app.ActivityManagerNative; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.PackageManager; 25 import android.content.pm.UserInfo; 26 import android.content.res.Resources; 27 import android.database.Cursor; 28 import android.graphics.Bitmap; 29 import android.graphics.drawable.Drawable; 30 import android.os.AsyncTask; 31 import android.os.RemoteException; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.provider.ContactsContract; 35 import android.util.Log; 36 import android.util.Pair; 37 38 import com.android.internal.util.UserIcons; 39 import com.android.settingslib.drawable.UserIconDrawable; 40 import com.android.systemui.R; 41 42 import java.util.ArrayList; 43 44 public final class UserInfoController { 45 46 private static final String TAG = "UserInfoController"; 47 48 private final Context mContext; 49 private final ArrayList<OnUserInfoChangedListener> mCallbacks = 50 new ArrayList<OnUserInfoChangedListener>(); 51 private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask; 52 53 private String mUserName; 54 private Drawable mUserDrawable; 55 56 public UserInfoController(Context context) { 57 mContext = context; 58 IntentFilter filter = new IntentFilter(); 59 filter.addAction(Intent.ACTION_USER_SWITCHED); 60 mContext.registerReceiver(mReceiver, filter); 61 62 IntentFilter profileFilter = new IntentFilter(); 63 profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); 64 profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); 65 mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, 66 null, null); 67 } 68 69 public void addListener(OnUserInfoChangedListener callback) { 70 mCallbacks.add(callback); 71 callback.onUserInfoChanged(mUserName, mUserDrawable); 72 } 73 74 public void remListener(OnUserInfoChangedListener callback) { 75 mCallbacks.remove(callback); 76 } 77 78 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 79 @Override 80 public void onReceive(Context context, Intent intent) { 81 final String action = intent.getAction(); 82 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 83 reloadUserInfo(); 84 } 85 } 86 }; 87 88 private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { 89 @Override 90 public void onReceive(Context context, Intent intent) { 91 final String action = intent.getAction(); 92 if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || 93 Intent.ACTION_USER_INFO_CHANGED.equals(action)) { 94 try { 95 final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id; 96 final int changedUser = 97 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); 98 if (changedUser == currentUser) { 99 reloadUserInfo(); 100 } 101 } catch (RemoteException e) { 102 Log.e(TAG, "Couldn't get current user id for profile change", e); 103 } 104 } 105 } 106 }; 107 108 public void reloadUserInfo() { 109 if (mUserInfoTask != null) { 110 mUserInfoTask.cancel(false); 111 mUserInfoTask = null; 112 } 113 queryForUserInformation(); 114 } 115 116 private void queryForUserInformation() { 117 Context currentUserContext; 118 UserInfo userInfo; 119 try { 120 userInfo = ActivityManagerNative.getDefault().getCurrentUser(); 121 currentUserContext = mContext.createPackageContextAsUser("android", 0, 122 new UserHandle(userInfo.id)); 123 } catch (PackageManager.NameNotFoundException e) { 124 Log.e(TAG, "Couldn't create user context", e); 125 throw new RuntimeException(e); 126 } catch (RemoteException e) { 127 Log.e(TAG, "Couldn't get user info", e); 128 throw new RuntimeException(e); 129 } 130 final int userId = userInfo.id; 131 final boolean isGuest = userInfo.isGuest(); 132 final String userName = userInfo.name; 133 134 final Resources res = mContext.getResources(); 135 final int avatarSize = Math.max( 136 res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size), 137 res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size)); 138 139 final Context context = currentUserContext; 140 mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() { 141 @Override 142 protected Pair<String, Drawable> doInBackground(Void... params) { 143 final UserManager um = UserManager.get(mContext); 144 145 // Fall back to the UserManager nickname if we can't read the name from the local 146 // profile below. 147 String name = userName; 148 Drawable avatar = null; 149 Bitmap rawAvatar = um.getUserIcon(userId); 150 if (rawAvatar != null) { 151 avatar = new UserIconDrawable(avatarSize) 152 .setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake(); 153 } else { 154 avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId, 155 /* light= */ true); 156 } 157 158 // If it's a single-user device, get the profile name, since the nickname is not 159 // usually valid 160 if (um.getUsers().size() <= 1) { 161 // Try and read the display name from the local profile 162 final Cursor cursor = context.getContentResolver().query( 163 ContactsContract.Profile.CONTENT_URI, new String[] { 164 ContactsContract.CommonDataKinds.Phone._ID, 165 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME 166 }, null, null, null); 167 if (cursor != null) { 168 try { 169 if (cursor.moveToFirst()) { 170 name = cursor.getString(cursor.getColumnIndex( 171 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); 172 } 173 } finally { 174 cursor.close(); 175 } 176 } 177 } 178 return new Pair<String, Drawable>(name, avatar); 179 } 180 181 @Override 182 protected void onPostExecute(Pair<String, Drawable> result) { 183 mUserName = result.first; 184 mUserDrawable = result.second; 185 mUserInfoTask = null; 186 notifyChanged(); 187 } 188 }; 189 mUserInfoTask.execute(); 190 } 191 192 private void notifyChanged() { 193 for (OnUserInfoChangedListener listener : mCallbacks) { 194 listener.onUserInfoChanged(mUserName, mUserDrawable); 195 } 196 } 197 198 public void onDensityOrFontScaleChanged() { 199 reloadUserInfo(); 200 } 201 202 public interface OnUserInfoChangedListener { 203 public void onUserInfoChanged(String name, Drawable picture); 204 } 205 } 206