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