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