Home | History | Annotate | Download | only in policy
      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