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