UserAvatarView.java revision a9459755c6e8b9de2b641b6f3874b815e5a82b8d
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 17package com.android.systemui.statusbar.phone; 18 19import com.android.systemui.R; 20 21import android.content.Context; 22import android.content.res.TypedArray; 23import android.graphics.Bitmap; 24import android.graphics.BitmapShader; 25import android.graphics.Canvas; 26import android.graphics.Color; 27import android.graphics.PorterDuff; 28import android.graphics.PorterDuffColorFilter; 29import android.graphics.Matrix; 30import android.graphics.Paint; 31import android.graphics.Shader; 32import android.graphics.drawable.Drawable; 33import android.util.AttributeSet; 34import android.view.View; 35 36/** 37 * A view that displays a user image cropped to a circle with a frame. 38 */ 39public class UserAvatarView extends View { 40 41 private int mActiveFrameColor; 42 private int mFrameColor; 43 private float mFrameWidth; 44 private float mFramePadding; 45 private Bitmap mBitmap; 46 private Drawable mDrawable; 47 private boolean mIsDisabled; 48 49 private final Paint mFramePaint = new Paint(); 50 private final Paint mBitmapPaint = new Paint(); 51 private final Matrix mDrawMatrix = new Matrix(); 52 53 private float mScale = 1; 54 55 public UserAvatarView(Context context, AttributeSet attrs, 56 int defStyleAttr, 57 int defStyleRes) { 58 super(context, attrs, defStyleAttr, defStyleRes); 59 final TypedArray a = context.obtainStyledAttributes( 60 attrs, R.styleable.UserAvatarView, defStyleAttr, defStyleRes); 61 final int N = a.getIndexCount(); 62 for (int i = 0; i < N; i++) { 63 int attr = a.getIndex(i); 64 switch (attr) { 65 case R.styleable.UserAvatarView_frameWidth: 66 setFrameWidth(a.getDimension(attr, 0)); 67 break; 68 case R.styleable.UserAvatarView_framePadding: 69 setFramePadding(a.getDimension(attr, 0)); 70 break; 71 case R.styleable.UserAvatarView_activeFrameColor: 72 setActiveFrameColor(a.getColor(attr, 0)); 73 break; 74 case R.styleable.UserAvatarView_frameColor: 75 setFrameColor(a.getColor(attr, 0)); 76 break; 77 } 78 } 79 a.recycle(); 80 81 mFramePaint.setAntiAlias(true); 82 mFramePaint.setStyle(Paint.Style.STROKE); 83 mBitmapPaint.setAntiAlias(true); 84 } 85 86 public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) { 87 this(context, attrs, defStyleAttr, 0); 88 } 89 90 public UserAvatarView(Context context, AttributeSet attrs) { 91 this(context, attrs, 0); 92 } 93 94 public UserAvatarView(Context context) { 95 this(context, null); 96 } 97 98 public void setBitmap(Bitmap bitmap) { 99 setDrawable(null); 100 mBitmap = bitmap; 101 if (mBitmap != null) { 102 mBitmapPaint.setShader(new BitmapShader( 103 bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); 104 } else { 105 mBitmapPaint.setShader(null); 106 } 107 configureBounds(); 108 invalidate(); 109 } 110 111 public void setFrameColor(int frameColor) { 112 mFrameColor = frameColor; 113 invalidate(); 114 } 115 116 public void setActiveFrameColor(int activeFrameColor) { 117 mActiveFrameColor = activeFrameColor; 118 invalidate(); 119 } 120 121 public void setFrameWidth(float frameWidth) { 122 mFrameWidth = frameWidth; 123 invalidate(); 124 } 125 126 public void setFramePadding(float framePadding) { 127 mFramePadding = framePadding; 128 invalidate(); 129 } 130 131 @Override 132 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 133 super.onLayout(changed, left, top, right, bottom); 134 configureBounds(); 135 } 136 137 public void configureBounds() { 138 int vwidth = getWidth() - mPaddingLeft - mPaddingRight; 139 int vheight = getHeight() - mPaddingTop - mPaddingBottom; 140 141 int dwidth; 142 int dheight; 143 if (mBitmap != null) { 144 dwidth = mBitmap.getWidth(); 145 dheight = mBitmap.getHeight(); 146 } else if (mDrawable != null) { 147 vwidth -= 2 * (mFrameWidth - 1); 148 vheight -= 2 * (mFrameWidth - 1); 149 dwidth = vwidth; 150 dheight = vheight; 151 mDrawable.setBounds(0, 0, dwidth, dheight); 152 } else { 153 return; 154 } 155 156 float scale; 157 float dx; 158 float dy; 159 160 scale = Math.min((float) vwidth / (float) dwidth, 161 (float) vheight / (float) dheight); 162 163 dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f); 164 dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); 165 166 mDrawMatrix.setScale(scale, scale); 167 mDrawMatrix.postTranslate(dx, dy); 168 mScale = scale; 169 } 170 171 @Override 172 protected void onDraw(Canvas canvas) { 173 int frameColor = isActivated() ? mActiveFrameColor : mFrameColor; 174 float halfW = getWidth() / 2f; 175 float halfH = getHeight() / 2f; 176 float halfSW = Math.min(halfH, halfW); 177 updateDrawableIfDisabled(); 178 if (mBitmap != null && mScale > 0) { 179 int saveCount = canvas.getSaveCount(); 180 canvas.save(); 181 canvas.translate(mPaddingLeft, mPaddingTop); 182 canvas.concat(mDrawMatrix); 183 float halfBW = mBitmap.getWidth() / 2f; 184 float halfBH = mBitmap.getHeight() / 2f; 185 float halfBSW = Math.min(halfBH, halfBW); 186 canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint); 187 canvas.restoreToCount(saveCount); 188 } else if (mDrawable != null && mScale > 0) { 189 int saveCount = canvas.getSaveCount(); 190 canvas.save(); 191 canvas.translate(mPaddingLeft, mPaddingTop); 192 canvas.translate(mFrameWidth - 1, mFrameWidth - 1); 193 canvas.concat(mDrawMatrix); 194 mDrawable.draw(canvas); 195 canvas.restoreToCount(saveCount); 196 } 197 if (frameColor != 0) { 198 mFramePaint.setColor(frameColor); 199 mFramePaint.setStrokeWidth(mFrameWidth); 200 canvas.drawCircle(halfW, halfH, halfSW + (mFramePadding - mFrameWidth) / 2f, 201 mFramePaint); 202 } 203 } 204 205 public void setDrawable(Drawable d) { 206 if (mDrawable != null) { 207 mDrawable.setCallback(null); 208 unscheduleDrawable(mDrawable); 209 } 210 mDrawable = d; 211 if (d != null) { 212 d.setCallback(this); 213 if (d.isStateful()) { 214 d.setState(getDrawableState()); 215 } 216 d.setLayoutDirection(getLayoutDirection()); 217 configureBounds(); 218 } 219 if (d != null) { 220 mBitmap = null; 221 } 222 configureBounds(); 223 invalidate(); 224 } 225 226 @Override 227 public void invalidateDrawable(Drawable dr) { 228 if (dr == mDrawable) { 229 invalidate(); 230 } else { 231 super.invalidateDrawable(dr); 232 } 233 } 234 235 @Override 236 protected boolean verifyDrawable(Drawable who) { 237 return who == mDrawable || super.verifyDrawable(who); 238 } 239 240 @Override 241 protected void drawableStateChanged() { 242 super.drawableStateChanged(); 243 if (mDrawable != null && mDrawable.isStateful()) { 244 mDrawable.setState(getDrawableState()); 245 } 246 } 247 248 public void setDisabled(boolean disabled) { 249 if (mIsDisabled == disabled) { 250 return; 251 } 252 mIsDisabled = disabled; 253 invalidate(); 254 } 255 256 private void updateDrawableIfDisabled() { 257 int disabledColor = getContext().getColor(R.color.qs_tile_disabled_color); 258 PorterDuffColorFilter filter = new PorterDuffColorFilter(disabledColor, 259 PorterDuff.Mode.SRC_ATOP); 260 if (mBitmap != null) { 261 if (mIsDisabled) { 262 mBitmapPaint.setColorFilter(filter); 263 } else { 264 mBitmapPaint.setColorFilter(null); 265 } 266 } else if (mDrawable != null) { 267 if (mIsDisabled) { 268 mDrawable.setColorFilter(filter); 269 } else { 270 mDrawable.setColorFilter(null); 271 } 272 } 273 } 274} 275