1 /* 2 * Copyright (C) 2012 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.keyguard; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.ValueAnimator.AnimatorUpdateListener; 22 import android.animation.ValueAnimator; 23 import android.content.Context; 24 import android.content.pm.UserInfo; 25 import android.content.res.Resources; 26 import android.graphics.Bitmap; 27 import android.graphics.BitmapFactory; 28 import android.graphics.Color; 29 import android.os.UserManager; 30 import android.util.AttributeSet; 31 import android.util.Log; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.widget.FrameLayout; 35 import android.widget.ImageView; 36 import android.widget.TextView; 37 38 class KeyguardMultiUserAvatar extends FrameLayout { 39 private static final String TAG = KeyguardMultiUserAvatar.class.getSimpleName(); 40 private static final boolean DEBUG = KeyguardHostView.DEBUG; 41 42 private ImageView mUserImage; 43 private TextView mUserName; 44 private UserInfo mUserInfo; 45 private static final float ACTIVE_ALPHA = 1.0f; 46 private static final float INACTIVE_ALPHA = 1.0f; 47 private static final float ACTIVE_SCALE = 1.5f; 48 private static final float ACTIVE_TEXT_ALPHA = 0f; 49 private static final float INACTIVE_TEXT_ALPHA = 0.5f; 50 private static final int SWITCH_ANIMATION_DURATION = 150; 51 52 private final float mActiveAlpha; 53 private final float mActiveScale; 54 private final float mActiveTextAlpha; 55 private final float mInactiveAlpha; 56 private final float mInactiveTextAlpha; 57 private final float mShadowRadius; 58 private final float mStroke; 59 private final float mIconSize; 60 private final int mFrameColor; 61 private final int mFrameShadowColor; 62 private final int mTextColor; 63 private final int mHighlightColor; 64 65 private boolean mTouched; 66 67 private boolean mActive; 68 private boolean mInit = true; 69 private KeyguardMultiUserSelectorView mUserSelector; 70 private KeyguardCircleFramedDrawable mFramed; 71 private boolean mPressLock; 72 private UserManager mUserManager; 73 fromXml(int resId, Context context, KeyguardMultiUserSelectorView userSelector, UserInfo info)74 public static KeyguardMultiUserAvatar fromXml(int resId, Context context, 75 KeyguardMultiUserSelectorView userSelector, UserInfo info) { 76 KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar) 77 LayoutInflater.from(context).inflate(resId, userSelector, false); 78 79 icon.init(info, userSelector); 80 return icon; 81 } 82 KeyguardMultiUserAvatar(Context context)83 public KeyguardMultiUserAvatar(Context context) { 84 this(context, null, 0); 85 } 86 KeyguardMultiUserAvatar(Context context, AttributeSet attrs)87 public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) { 88 this(context, attrs, 0); 89 } 90 KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle)91 public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) { 92 super(context, attrs, defStyle); 93 94 Resources res = mContext.getResources(); 95 mTextColor = res.getColor(R.color.keyguard_avatar_nick_color); 96 mIconSize = res.getDimension(R.dimen.keyguard_avatar_size); 97 mStroke = res.getDimension(R.dimen.keyguard_avatar_frame_stroke_width); 98 mShadowRadius = res.getDimension(R.dimen.keyguard_avatar_frame_shadow_radius); 99 mFrameColor = res.getColor(R.color.keyguard_avatar_frame_color); 100 mFrameShadowColor = res.getColor(R.color.keyguard_avatar_frame_shadow_color); 101 mHighlightColor = res.getColor(R.color.keyguard_avatar_frame_pressed_color); 102 mActiveTextAlpha = ACTIVE_TEXT_ALPHA; 103 mInactiveTextAlpha = INACTIVE_TEXT_ALPHA; 104 mActiveScale = ACTIVE_SCALE; 105 mActiveAlpha = ACTIVE_ALPHA; 106 mInactiveAlpha = INACTIVE_ALPHA; 107 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 108 109 mTouched = false; 110 111 setLayerType(View.LAYER_TYPE_SOFTWARE, null); 112 } 113 rewriteIconPath(String path)114 protected String rewriteIconPath(String path) { 115 return path; 116 } 117 init(UserInfo user, KeyguardMultiUserSelectorView userSelector)118 public void init(UserInfo user, KeyguardMultiUserSelectorView userSelector) { 119 mUserInfo = user; 120 mUserSelector = userSelector; 121 122 mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar); 123 mUserName = (TextView) findViewById(R.id.keyguard_user_name); 124 125 mFramed = (KeyguardCircleFramedDrawable) 126 KeyguardViewMediator.getAvatarCache().get(user.id); 127 128 // If we can't find it or the params don't match, create the drawable again 129 if (mFramed == null 130 || !mFramed.verifyParams(mIconSize, mFrameColor, mStroke, mFrameShadowColor, 131 mShadowRadius, mHighlightColor)) { 132 Bitmap icon = null; 133 try { 134 icon = mUserManager.getUserIcon(user.id); 135 } catch (Exception e) { 136 if (DEBUG) Log.d(TAG, "failed to get profile icon " + user, e); 137 } 138 139 if (icon == null) { 140 icon = BitmapFactory.decodeResource(mContext.getResources(), 141 com.android.internal.R.drawable.ic_contact_picture); 142 } 143 144 mFramed = new KeyguardCircleFramedDrawable(icon, (int) mIconSize, mFrameColor, mStroke, 145 mFrameShadowColor, mShadowRadius, mHighlightColor); 146 KeyguardViewMediator.getAvatarCache().put(user.id, mFramed); 147 } 148 149 mFramed.reset(); 150 151 mUserImage.setImageDrawable(mFramed); 152 mUserName.setText(mUserInfo.name); 153 setOnClickListener(mUserSelector); 154 mInit = false; 155 } 156 setActive(boolean active, boolean animate, final Runnable onComplete)157 public void setActive(boolean active, boolean animate, final Runnable onComplete) { 158 if (mActive != active || mInit) { 159 mActive = active; 160 161 if (active) { 162 KeyguardLinearLayout parent = (KeyguardLinearLayout) getParent(); 163 parent.setTopChild(this); 164 // TODO: Create an appropriate asset when string changes are possible. 165 setContentDescription(mUserName.getText() 166 + ". " + mContext.getString(R.string.user_switched, "")); 167 } else { 168 setContentDescription(mUserName.getText()); 169 } 170 } 171 updateVisualsForActive(mActive, animate, SWITCH_ANIMATION_DURATION, onComplete); 172 } 173 updateVisualsForActive(boolean active, boolean animate, int duration, final Runnable onComplete)174 void updateVisualsForActive(boolean active, boolean animate, int duration, 175 final Runnable onComplete) { 176 final float finalAlpha = active ? mActiveAlpha : mInactiveAlpha; 177 final float initAlpha = active ? mInactiveAlpha : mActiveAlpha; 178 final float finalScale = active ? 1f : 1f / mActiveScale; 179 final float initScale = mFramed.getScale(); 180 final int finalTextAlpha = active ? (int) (mActiveTextAlpha * 255) : 181 (int) (mInactiveTextAlpha * 255); 182 final int initTextAlpha = active ? (int) (mInactiveTextAlpha * 255) : 183 (int) (mActiveTextAlpha * 255); 184 int textColor = mTextColor; 185 mUserName.setTextColor(textColor); 186 187 if (animate && mTouched) { 188 ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 189 va.addUpdateListener(new AnimatorUpdateListener() { 190 @Override 191 public void onAnimationUpdate(ValueAnimator animation) { 192 float r = animation.getAnimatedFraction(); 193 float scale = (1 - r) * initScale + r * finalScale; 194 float alpha = (1 - r) * initAlpha + r * finalAlpha; 195 int textAlpha = (int) ((1 - r) * initTextAlpha + r * finalTextAlpha); 196 mFramed.setScale(scale); 197 mUserImage.setAlpha(alpha); 198 mUserName.setTextColor(Color.argb(textAlpha, 255, 255, 255)); 199 mUserImage.invalidate(); 200 } 201 }); 202 va.addListener(new AnimatorListenerAdapter() { 203 @Override 204 public void onAnimationEnd(Animator animation) { 205 if (onComplete != null) { 206 onComplete.run(); 207 } 208 } 209 }); 210 va.setDuration(duration); 211 va.start(); 212 } else { 213 mFramed.setScale(finalScale); 214 mUserImage.setAlpha(finalAlpha); 215 mUserName.setTextColor(Color.argb(finalTextAlpha, 255, 255, 255)); 216 if (onComplete != null) { 217 post(onComplete); 218 } 219 } 220 221 mTouched = true; 222 } 223 224 @Override setPressed(boolean pressed)225 public void setPressed(boolean pressed) { 226 if (mPressLock && !pressed) { 227 return; 228 } 229 230 if (mPressLock || !pressed || isClickable()) { 231 super.setPressed(pressed); 232 mFramed.setPressed(pressed); 233 mUserImage.invalidate(); 234 } 235 } 236 lockPressed(boolean pressed)237 public void lockPressed(boolean pressed) { 238 mPressLock = pressed; 239 setPressed(pressed); 240 } 241 getUserInfo()242 public UserInfo getUserInfo() { 243 return mUserInfo; 244 } 245 } 246