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.BitmapDrawable;
     30 import android.graphics.drawable.Drawable;
     31 import android.os.AsyncTask;
     32 import android.os.RemoteException;
     33 import android.os.UserHandle;
     34 import android.os.UserManager;
     35 import android.provider.ContactsContract;
     36 import android.util.Log;
     37 import android.util.Pair;
     38 
     39 import com.android.systemui.BitmapHelper;
     40 import com.android.systemui.R;
     41 import com.android.internal.util.UserIcons;
     42 
     43 import java.util.ArrayList;
     44 
     45 public final class UserInfoController {
     46 
     47     private static final String TAG = "UserInfoController";
     48 
     49     private final Context mContext;
     50     private final ArrayList<OnUserInfoChangedListener> mCallbacks =
     51             new ArrayList<OnUserInfoChangedListener>();
     52     private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
     53 
     54     private boolean mUseDefaultAvatar;
     55     private String mUserName;
     56     private Drawable mUserDrawable;
     57 
     58     public UserInfoController(Context context) {
     59         mContext = context;
     60         IntentFilter filter = new IntentFilter();
     61         filter.addAction(Intent.ACTION_USER_SWITCHED);
     62         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
     63         mContext.registerReceiver(mReceiver, filter);
     64 
     65         IntentFilter profileFilter = new IntentFilter();
     66         profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
     67         profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
     68         mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
     69                 null, null);
     70     }
     71 
     72     public void addListener(OnUserInfoChangedListener callback) {
     73         mCallbacks.add(callback);
     74     }
     75 
     76     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     77         @Override
     78         public void onReceive(Context context, Intent intent) {
     79             final String action = intent.getAction();
     80             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
     81                 reloadUserInfo();
     82             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
     83                 if (mUseDefaultAvatar) {
     84                     reloadUserInfo();
     85                 }
     86             }
     87         }
     88     };
     89 
     90     private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
     91         @Override
     92         public void onReceive(Context context, Intent intent) {
     93             final String action = intent.getAction();
     94             if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
     95                     Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
     96                 try {
     97                     final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
     98                     final int changedUser =
     99                             intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
    100                     if (changedUser == currentUser) {
    101                         reloadUserInfo();
    102                     }
    103                 } catch (RemoteException e) {
    104                     Log.e(TAG, "Couldn't get current user id for profile change", e);
    105                 }
    106             }
    107         }
    108     };
    109 
    110     public void reloadUserInfo() {
    111         if (mUserInfoTask != null) {
    112             mUserInfoTask.cancel(false);
    113             mUserInfoTask = null;
    114         }
    115         queryForUserInformation();
    116     }
    117 
    118     private void queryForUserInformation() {
    119         Context currentUserContext;
    120         UserInfo userInfo;
    121         try {
    122             userInfo = ActivityManagerNative.getDefault().getCurrentUser();
    123             currentUserContext = mContext.createPackageContextAsUser("android", 0,
    124                     new UserHandle(userInfo.id));
    125         } catch (PackageManager.NameNotFoundException e) {
    126             Log.e(TAG, "Couldn't create user context", e);
    127             throw new RuntimeException(e);
    128         } catch (RemoteException e) {
    129             Log.e(TAG, "Couldn't get user info", e);
    130             throw new RuntimeException(e);
    131         }
    132         final int userId = userInfo.id;
    133         final boolean isGuest = userInfo.isGuest();
    134         final String userName = userInfo.name;
    135 
    136         final Resources res = mContext.getResources();
    137         final int avatarSize = Math.max(
    138                 res.getDimensionPixelSize(R.dimen.multi_user_avatar_expanded_size),
    139                 res.getDimensionPixelSize(R.dimen.multi_user_avatar_keyguard_size));
    140 
    141         final Context context = currentUserContext;
    142         mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
    143             @Override
    144             protected Pair<String, Drawable> doInBackground(Void... params) {
    145                 final UserManager um = UserManager.get(mContext);
    146 
    147                 // Fall back to the UserManager nickname if we can't read the name from the local
    148                 // profile below.
    149                 String name = userName;
    150                 Drawable avatar = null;
    151                 Bitmap rawAvatar = um.getUserIcon(userId);
    152                 if (rawAvatar != null) {
    153                     avatar = new BitmapDrawable(mContext.getResources(),
    154                             BitmapHelper.createCircularClip(rawAvatar, avatarSize, avatarSize));
    155                 } else {
    156                     avatar = UserIcons.getDefaultUserIcon(isGuest? UserHandle.USER_NULL : userId,
    157                             /* light= */ true);
    158                     mUseDefaultAvatar = true;
    159                 }
    160 
    161                 // If it's a single-user device, get the profile name, since the nickname is not
    162                 // usually valid
    163                 if (um.getUsers().size() <= 1) {
    164                     // Try and read the display name from the local profile
    165                     final Cursor cursor = context.getContentResolver().query(
    166                             ContactsContract.Profile.CONTENT_URI, new String[] {
    167                                     ContactsContract.CommonDataKinds.Phone._ID,
    168                                     ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
    169                             }, null, null, null);
    170                     if (cursor != null) {
    171                         try {
    172                             if (cursor.moveToFirst()) {
    173                                 name = cursor.getString(cursor.getColumnIndex(
    174                                         ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
    175                             }
    176                         } finally {
    177                             cursor.close();
    178                         }
    179                     }
    180                 }
    181                 return new Pair<String, Drawable>(name, avatar);
    182             }
    183 
    184             @Override
    185             protected void onPostExecute(Pair<String, Drawable> result) {
    186                 mUserName = result.first;
    187                 mUserDrawable = result.second;
    188                 mUserInfoTask = null;
    189                 notifyChanged();
    190             }
    191         };
    192         mUserInfoTask.execute();
    193     }
    194 
    195     private void notifyChanged() {
    196         for (OnUserInfoChangedListener listener : mCallbacks) {
    197             listener.onUserInfoChanged(mUserName, mUserDrawable);
    198         }
    199     }
    200 
    201     public interface OnUserInfoChangedListener {
    202         public void onUserInfoChanged(String name, Drawable picture);
    203     }
    204 }
    205