Merge "Cache the scaled avatar drawables in the keyguard user switcher" into jb-mr2-dev
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bfc7bf5..65f904f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2567,8 +2567,7 @@
     /**
      * Broadcast sent to the system when a user's information changes. Carries an extra
      * {@link #EXTRA_USER_HANDLE} to indicate which user's information changed.
-     * This is only sent to registered receivers, not manifest receivers. It is sent to the user
-     * whose information has changed.
+     * This is only sent to registered receivers, not manifest receivers. It is sent to all users.
      * @hide
      */
     public static final String ACTION_USER_INFO_CHANGED =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index d826282..df1eb67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -819,8 +819,10 @@
             if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
                     Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
                 try {
-                    final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
-                    if (getSendingUserId() == userId) {
+                    final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+                    final int changedUser =
+                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
+                    if (changedUser == currentUser) {
                         reloadUserInfo();
                     }
                 } catch (RemoteException e) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
index 79b66f4..fe32099 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardCircleFramedDrawable.java
@@ -100,6 +100,11 @@
         mFramePath = new Path();
     }
 
+    public void reset() {
+        mScale = 1f;
+        mPressed = false;
+    }
+
     @Override
     public void draw(Canvas canvas) {
         // clear background
@@ -157,4 +162,14 @@
     @Override
     public void setColorFilter(ColorFilter cf) {
     }
+
+    public boolean verifyParams(float iconSize, int frameColor, float stroke,
+            int frameShadowColor, float shadowRadius, int highlightColor) {
+        return mSize == iconSize
+                && mFrameColor == frameColor
+                && mStrokeWidth == stroke
+                && mFrameShadowColor == frameShadowColor
+                && mShadowRadius == shadowRadius
+                && mHighlightColor == highlightColor;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
index 9d1f041..387e0ce 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
@@ -124,20 +124,32 @@
         mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
         mUserName = (TextView) findViewById(R.id.keyguard_user_name);
 
-        Bitmap icon = null; 
-        try {
-            icon = BitmapFactory.decodeFile(rewriteIconPath(user.iconPath));
-        } catch (Exception e) {
-            if (DEBUG) Log.d(TAG, "failed to open profile icon " + user.iconPath, e);
+        mFramed = (KeyguardCircleFramedDrawable)
+                KeyguardViewMediator.getAvatarCache().get(user.id);
+
+        // If we can't find it or the params don't match, create the drawable again
+        if (mFramed == null
+                || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor,
+                        mShadowRadius, mHighlightColor)) {
+            Bitmap icon = null;
+            try {
+                icon = BitmapFactory.decodeFile(rewriteIconPath(user.iconPath));
+            } catch (Exception e) {
+                if (DEBUG) Log.d(TAG, "failed to open profile icon " + user.iconPath, e);
+            }
+
+            if (icon == null) {
+                icon = BitmapFactory.decodeResource(mContext.getResources(),
+                        com.android.internal.R.drawable.ic_contact_picture);
+            }
+
+            mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
+                    mFrameShadowColor, mShadowRadius, mHighlightColor);
+            KeyguardViewMediator.getAvatarCache().put(user.id, mFramed);
         }
 
-        if (icon == null) {
-            icon = BitmapFactory.decodeResource(mContext.getResources(),
-                    com.android.internal.R.drawable.ic_contact_picture);
-        }
+        mFramed.reset();
 
-        mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke,
-                mFrameShadowColor, mShadowRadius, mHighlightColor);
         mUserImage.setImageDrawable(mFramed);
         mUserName.setText(mUserInfo.name);
         setOnClickListener(mUserSelector);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 986dc49..5a64586 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -91,6 +91,7 @@
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
     private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
     protected static final int MSG_SET_PLAYBACK_STATE = 316;
+    protected static final int MSG_USER_INFO_CHANGED = 317;
 
 
     private static KeyguardUpdateMonitor sInstance;
@@ -178,6 +179,9 @@
                 case MSG_SET_PLAYBACK_STATE:
                     handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
                     break;
+                case MSG_USER_INFO_CHANGED:
+                    handleUserInfoChanged(msg.arg1);
+                    break;
             }
         }
     };
@@ -280,6 +284,17 @@
         }
     };
 
+    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
+
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
+            }
+        }
+    };
+
     /**
      * When we receive a
      * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
@@ -389,7 +404,6 @@
         return sInstance;
     }
 
-
     protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
         mDisplayClientState.clientGeneration = clientGeneration;
         mDisplayClientState.clearing = clearing;
@@ -422,6 +436,15 @@
         }
     }
 
+    private void handleUserInfoChanged(int userId) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserInfoChanged(userId);
+            }
+        }
+    }
+
     private KeyguardUpdateMonitor(Context context) {
         mContext = context;
 
@@ -456,6 +479,10 @@
         bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
         context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
 
+        final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED);
+        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter,
+                null, null);
+
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
                     new IUserSwitchObserver.Stub() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
index 368ccb3..41816db 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
@@ -107,6 +107,11 @@
     void onUserRemoved(int userId) { }
 
     /**
+     * Called when the user's info changed.
+     */
+    void onUserInfoChanged(int userId) { }
+
+    /**
      * Called when boot completed.
      *
      * Note, this callback will only be received if boot complete occurs after registering with
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 08a95a6..885cb45 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -254,6 +254,11 @@
     private final float mLockSoundVolume;
 
     /**
+     * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
+     */
+    private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
+
+    /**
      * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
      * various things.
      */
@@ -333,6 +338,12 @@
         @Override
         public void onUserRemoved(int userId) {
             mLockPatternUtils.removeUser(userId);
+            sMultiUserAvatarCache.clear(userId);
+        }
+
+        @Override
+        public void onUserInfoChanged(int userId) {
+            sMultiUserAvatarCache.clear(userId);
         }
 
         @Override
@@ -1431,4 +1442,8 @@
         return mSearchManager != null
                 && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
     }
+
+    public static MultiUserAvatarCache getAvatarCache() {
+        return sMultiUserAvatarCache;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java
new file mode 100644
index 0000000..7969c7d
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiUserAvatarCache.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl.keyguard;
+
+import android.graphics.drawable.Drawable;
+
+import java.util.HashMap;
+
+public class MultiUserAvatarCache {
+
+    private final HashMap<Integer, Drawable> mCache;
+
+    public MultiUserAvatarCache() {
+        mCache = new HashMap<Integer, Drawable>();
+    }
+
+    public void clear(int userId) {
+        mCache.remove(userId);
+    }
+
+    public Drawable get(int userId) {
+        return mCache.get(userId);
+    }
+
+    public void put(int userId, Drawable image) {
+        mCache.put(userId, image);
+    }
+}
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 11c6dab..1323c93 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -296,7 +296,7 @@
         Intent changedIntent = new Intent(Intent.ACTION_USER_INFO_CHANGED);
         changedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
         changedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mContext.sendBroadcastAsUser(changedIntent, new UserHandle(userId));
+        mContext.sendBroadcastAsUser(changedIntent, UserHandle.ALL);
     }
 
     @Override