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.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.pm.PackageManager; 24 import android.content.pm.UserInfo; 25 import android.content.res.Resources; 26 import android.database.Cursor; 27 import android.graphics.Bitmap; 28 import android.graphics.drawable.Drawable; 29 import android.os.AsyncTask; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.provider.ContactsContract; 33 import android.util.Log; 34 35 import androidx.annotation.NonNull; 36 37 import com.android.internal.util.UserIcons; 38 import com.android.settingslib.drawable.UserIconDrawable; 39 import com.android.systemui.R; 40 import com.android.systemui.dagger.SysUISingleton; 41 import com.android.systemui.dagger.qualifiers.Main; 42 import com.android.systemui.settings.UserTracker; 43 44 import java.util.ArrayList; 45 import java.util.concurrent.Executor; 46 47 import javax.inject.Inject; 48 49 /** 50 */ 51 @SysUISingleton 52 public class UserInfoControllerImpl implements UserInfoController { 53 54 private static final String TAG = "UserInfoController"; 55 56 private final Context mContext; 57 private final UserTracker mUserTracker; 58 private final ArrayList<OnUserInfoChangedListener> mCallbacks = 59 new ArrayList<OnUserInfoChangedListener>(); 60 private AsyncTask<Void, Void, UserInfoQueryResult> mUserInfoTask; 61 62 private String mUserName; 63 private Drawable mUserDrawable; 64 private String mUserAccount; 65 66 /** 67 */ 68 @Inject UserInfoControllerImpl(Context context, @Main Executor mainExecutor, UserTracker userTracker)69 public UserInfoControllerImpl(Context context, @Main Executor mainExecutor, 70 UserTracker userTracker) { 71 mContext = context; 72 mUserTracker = userTracker; 73 mUserTracker.addCallback(mUserChangedCallback, mainExecutor); 74 75 IntentFilter profileFilter = new IntentFilter(); 76 profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED); 77 profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); 78 mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter, 79 null, null, Context.RECEIVER_EXPORTED_UNAUDITED); 80 } 81 82 @Override addCallback(@onNull OnUserInfoChangedListener callback)83 public void addCallback(@NonNull OnUserInfoChangedListener callback) { 84 mCallbacks.add(callback); 85 callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); 86 } 87 88 @Override removeCallback(@onNull OnUserInfoChangedListener callback)89 public void removeCallback(@NonNull OnUserInfoChangedListener callback) { 90 mCallbacks.remove(callback); 91 } 92 93 private final UserTracker.Callback mUserChangedCallback = 94 new UserTracker.Callback() { 95 @Override 96 public void onUserChanged(int newUser, @NonNull Context userContext) { 97 reloadUserInfo(); 98 } 99 }; 100 101 private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() { 102 @Override 103 public void onReceive(Context context, Intent intent) { 104 final String action = intent.getAction(); 105 if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) || 106 Intent.ACTION_USER_INFO_CHANGED.equals(action)) { 107 final int currentUser = mUserTracker.getUserId(); 108 final int changedUser = 109 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()); 110 if (changedUser == currentUser) { 111 reloadUserInfo(); 112 } 113 } 114 } 115 }; 116 reloadUserInfo()117 public void reloadUserInfo() { 118 if (mUserInfoTask != null) { 119 mUserInfoTask.cancel(false); 120 mUserInfoTask = null; 121 } 122 queryForUserInformation(); 123 } 124 queryForUserInformation()125 private void queryForUserInformation() { 126 Context currentUserContext; 127 UserInfo userInfo; 128 try { 129 userInfo = mUserTracker.getUserInfo(); 130 currentUserContext = mContext.createPackageContextAsUser("android", 0, 131 new UserHandle(userInfo.id)); 132 } catch (PackageManager.NameNotFoundException e) { 133 Log.e(TAG, "Couldn't create user context", e); 134 throw new RuntimeException(e); 135 } 136 final int userId = userInfo.id; 137 final boolean isGuest = userInfo.isGuest(); 138 final String userName = userInfo.name; 139 final boolean lightIcon = mContext.getThemeResId() != R.style.Theme_SystemUI_LightWallpaper; 140 141 final Resources res = mContext.getResources(); 142 final int avatarSize = Math.max( 143 res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size), 144 res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size)); 145 146 final Context context = currentUserContext; 147 mUserInfoTask = new AsyncTask<Void, Void, UserInfoQueryResult>() { 148 149 @Override 150 protected UserInfoQueryResult doInBackground(Void... params) { 151 final UserManager um = UserManager.get(mContext); 152 153 // Fall back to the UserManager nickname if we can't read the name from the local 154 // profile below. 155 String name = userName; 156 Drawable avatar = null; 157 Bitmap rawAvatar = um.getUserIcon(userId); 158 if (rawAvatar != null) { 159 avatar = new UserIconDrawable(avatarSize) 160 .setIcon(rawAvatar).setBadgeIfManagedUser(mContext, userId).bake(); 161 } else { 162 avatar = UserIcons.getDefaultUserIcon( 163 context.getResources(), 164 isGuest? UserHandle.USER_NULL : userId, 165 lightIcon); 166 } 167 168 // If it's a single-user device, get the profile name, since the nickname is not 169 // usually valid 170 if (um.getUsers().size() <= 1) { 171 // Try and read the display name from the local profile 172 final Cursor cursor = context.getContentResolver().query( 173 ContactsContract.Profile.CONTENT_URI, new String[] { 174 ContactsContract.CommonDataKinds.Phone._ID, 175 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME 176 }, null, null, null); 177 if (cursor != null) { 178 try { 179 if (cursor.moveToFirst()) { 180 name = cursor.getString(cursor.getColumnIndex( 181 ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); 182 } 183 } finally { 184 cursor.close(); 185 } 186 } 187 } 188 String userAccount = um.getUserAccount(userId); 189 return new UserInfoQueryResult(name, avatar, userAccount); 190 } 191 192 @Override 193 protected void onPostExecute(UserInfoQueryResult result) { 194 mUserName = result.getName(); 195 mUserDrawable = result.getAvatar(); 196 mUserAccount = result.getUserAccount(); 197 mUserInfoTask = null; 198 notifyChanged(); 199 } 200 }; 201 mUserInfoTask.execute(); 202 } 203 notifyChanged()204 private void notifyChanged() { 205 for (OnUserInfoChangedListener listener : mCallbacks) { 206 listener.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); 207 } 208 } 209 onDensityOrFontScaleChanged()210 public void onDensityOrFontScaleChanged() { 211 reloadUserInfo(); 212 } 213 214 private static class UserInfoQueryResult { 215 private String mName; 216 private Drawable mAvatar; 217 private String mUserAccount; 218 UserInfoQueryResult(String name, Drawable avatar, String userAccount)219 public UserInfoQueryResult(String name, Drawable avatar, String userAccount) { 220 mName = name; 221 mAvatar = avatar; 222 mUserAccount = userAccount; 223 } 224 getName()225 public String getName() { 226 return mName; 227 } 228 getAvatar()229 public Drawable getAvatar() { 230 return mAvatar; 231 } 232 getUserAccount()233 public String getUserAccount() { 234 return mUserAccount; 235 } 236 } 237 } 238