1 /* 2 * Copyright (C) 2013 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.settings.drawable; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.graphics.Bitmap; 22 import android.graphics.Canvas; 23 import android.graphics.Color; 24 import android.graphics.ColorFilter; 25 import android.graphics.Paint; 26 import android.graphics.Path; 27 import android.graphics.PixelFormat; 28 import android.graphics.PorterDuff; 29 import android.graphics.PorterDuffXfermode; 30 import android.graphics.Rect; 31 import android.graphics.RectF; 32 import android.graphics.drawable.Drawable; 33 34 import com.android.settings.R; 35 36 /** 37 * Converts the user avatar icon to a circularly clipped one. 38 * TODO: Move this to an internal framework class and share with the one in Keyguard. 39 */ 40 public class CircleFramedDrawable extends Drawable { 41 42 private final Bitmap mBitmap; 43 private final int mSize; 44 private final Paint mPaint; 45 private final float mShadowRadius; 46 private final float mStrokeWidth; 47 private final int mFrameColor; 48 private final int mHighlightColor; 49 private final int mFrameShadowColor; 50 51 private float mScale; 52 private Path mFramePath; 53 private Rect mSrcRect; 54 private RectF mDstRect; 55 private RectF mFrameRect; 56 private boolean mPressed; 57 getInstance(Context context, Bitmap icon)58 public static CircleFramedDrawable getInstance(Context context, Bitmap icon) { 59 Resources res = context.getResources(); 60 float iconSize = res.getDimension(R.dimen.circle_avatar_size); 61 float strokeWidth = res.getDimension(R.dimen.circle_avatar_frame_stroke_width); 62 float shadowRadius = res.getDimension(R.dimen.circle_avatar_frame_shadow_radius); 63 int frameColor = res.getColor(R.color.circle_avatar_frame_color); 64 int frameShadowColor = res.getColor(R.color.circle_avatar_frame_shadow_color); 65 int highlightColor = res.getColor(R.color.circle_avatar_frame_pressed_color); 66 67 CircleFramedDrawable instance = new CircleFramedDrawable(icon, 68 (int) iconSize, frameColor, strokeWidth, frameShadowColor, shadowRadius, 69 highlightColor); 70 return instance; 71 } 72 CircleFramedDrawable(Bitmap icon, int size, int frameColor, float strokeWidth, int frameShadowColor, float shadowRadius, int highlightColor)73 public CircleFramedDrawable(Bitmap icon, int size, 74 int frameColor, float strokeWidth, 75 int frameShadowColor, float shadowRadius, 76 int highlightColor) { 77 super(); 78 mSize = size; 79 mShadowRadius = shadowRadius; 80 mFrameColor = frameColor; 81 mFrameShadowColor = frameShadowColor; 82 mStrokeWidth = strokeWidth; 83 mHighlightColor = highlightColor; 84 85 mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888); 86 final Canvas canvas = new Canvas(mBitmap); 87 88 final int width = icon.getWidth(); 89 final int height = icon.getHeight(); 90 final int square = Math.min(width, height); 91 92 final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square); 93 final RectF circleRect = new RectF(0f, 0f, mSize, mSize); 94 circleRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); 95 circleRect.inset(mShadowRadius, mShadowRadius); 96 97 final Path fillPath = new Path(); 98 fillPath.addArc(circleRect, 0f, 360f); 99 100 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 101 102 // opaque circle matte 103 mPaint = new Paint(); 104 mPaint.setAntiAlias(true); 105 mPaint.setColor(Color.BLACK); 106 mPaint.setStyle(Paint.Style.FILL); 107 canvas.drawPath(fillPath, mPaint); 108 109 // mask in the icon where the bitmap is opaque 110 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 111 canvas.drawBitmap(icon, cropRect, circleRect, mPaint); 112 113 // prepare paint for frame drawing 114 mPaint.setXfermode(null); 115 116 mScale = 1f; 117 118 mSrcRect = new Rect(0, 0, mSize, mSize); 119 mDstRect = new RectF(0, 0, mSize, mSize); 120 mFrameRect = new RectF(mDstRect); 121 mFramePath = new Path(); 122 } 123 124 @Override draw(Canvas canvas)125 public void draw(Canvas canvas) { 126 final float inside = mScale * mSize; 127 final float pad = (mSize - inside) / 2f; 128 129 mDstRect.set(pad, pad, mSize - pad, mSize - pad); 130 canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null); 131 132 mFrameRect.set(mDstRect); 133 mFrameRect.inset(mStrokeWidth / 2f, mStrokeWidth / 2f); 134 mFrameRect.inset(mShadowRadius, mShadowRadius); 135 136 mFramePath.reset(); 137 mFramePath.addArc(mFrameRect, 0f, 360f); 138 139 // white frame 140 if (mPressed) { 141 mPaint.setStyle(Paint.Style.FILL); 142 mPaint.setColor(Color.argb((int) (0.33f * 255), 143 Color.red(mHighlightColor), 144 Color.green(mHighlightColor), 145 Color.blue(mHighlightColor))); 146 canvas.drawPath(mFramePath, mPaint); 147 } 148 mPaint.setStrokeWidth(mStrokeWidth); 149 mPaint.setStyle(Paint.Style.STROKE); 150 mPaint.setColor(mPressed ? mHighlightColor : mFrameColor); 151 mPaint.setShadowLayer(mShadowRadius, 0f, 0f, mFrameShadowColor); 152 canvas.drawPath(mFramePath, mPaint); 153 } 154 setScale(float scale)155 public void setScale(float scale) { 156 mScale = scale; 157 } 158 getScale()159 public float getScale() { 160 return mScale; 161 } 162 setPressed(boolean pressed)163 public void setPressed(boolean pressed) { 164 mPressed = pressed; 165 } 166 167 @Override getOpacity()168 public int getOpacity() { 169 return PixelFormat.TRANSLUCENT; 170 } 171 172 @Override setAlpha(int alpha)173 public void setAlpha(int alpha) { 174 } 175 176 @Override setColorFilter(ColorFilter cf)177 public void setColorFilter(ColorFilter cf) { 178 } 179 180 @Override getIntrinsicWidth()181 public int getIntrinsicWidth() { 182 return mSize; 183 } 184 185 @Override getIntrinsicHeight()186 public int getIntrinsicHeight() { 187 return mSize; 188 } 189 } 190