UserAvatarView.java revision 8ddb2da8759c29b3968b4d6bb9488f59a19f0ff2
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.Matrix;
27import android.graphics.Paint;
28import android.graphics.Shader;
29import android.graphics.drawable.Drawable;
30import android.util.AttributeSet;
31import android.view.View;
32
33/**
34 * A view that displays a user image cropped to a circle with a frame.
35 */
36public class UserAvatarView extends View {
37
38    private int mActiveFrameColor;
39    private int mFrameColor;
40    private float mFrameWidth;
41    private Bitmap mBitmap;
42    private Drawable mDrawable;
43
44    private final Paint mFramePaint = new Paint();
45    private final Paint mBitmapPaint = new Paint();
46    private final Matrix mDrawMatrix = new Matrix();
47
48    private float mScale = 1;
49
50    public UserAvatarView(Context context, AttributeSet attrs,
51            int defStyleAttr,
52            int defStyleRes) {
53        super(context, attrs, defStyleAttr, defStyleRes);
54        final TypedArray a = context.obtainStyledAttributes(
55                attrs, R.styleable.UserAvatarView, defStyleAttr, defStyleRes);
56        final int N = a.getIndexCount();
57        for (int i = 0; i < N; i++) {
58            int attr = a.getIndex(i);
59            switch (attr) {
60                case R.styleable.UserAvatarView_frameWidth:
61                    setFrameWidth(a.getDimension(attr, 0));
62                    break;
63                case R.styleable.UserAvatarView_activeFrameColor:
64                    setActiveFrameColor(a.getColor(attr, 0));
65                    break;
66                case R.styleable.UserAvatarView_frameColor:
67                    setFrameColor(a.getColor(attr, 0));
68                    break;
69            }
70        }
71        a.recycle();
72
73        mFramePaint.setAntiAlias(true);
74        mFramePaint.setStyle(Paint.Style.STROKE);
75        mBitmapPaint.setAntiAlias(true);
76    }
77
78    public UserAvatarView(Context context, AttributeSet attrs, int defStyleAttr) {
79        this(context, attrs, defStyleAttr, 0);
80    }
81
82    public UserAvatarView(Context context, AttributeSet attrs) {
83        this(context, attrs, 0);
84    }
85
86    public UserAvatarView(Context context) {
87        this(context, null);
88    }
89
90    public void setBitmap(Bitmap bitmap) {
91        setDrawable(null);
92        mBitmap = bitmap;
93        mBitmapPaint.setShader(new BitmapShader(
94                bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
95        configureBounds();
96        invalidate();
97    }
98
99    public void setFrameColor(int frameColor) {
100        mFrameColor = frameColor;
101        invalidate();
102    }
103
104    public void setActiveFrameColor(int activeFrameColor) {
105        mActiveFrameColor = activeFrameColor;
106        invalidate();
107    }
108
109    public void setFrameWidth(float frameWidth) {
110        mFrameWidth = frameWidth;
111        invalidate();
112    }
113
114    @Override
115    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
116        super.onLayout(changed, left, top, right, bottom);
117        configureBounds();
118    }
119
120    public void configureBounds() {
121        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
122        int vheight = getHeight() - mPaddingTop - mPaddingBottom;
123
124        int dwidth;
125        int dheight;
126        if (mBitmap != null) {
127            dwidth = mBitmap.getWidth();
128            dheight = mBitmap.getHeight();
129        } else if (mDrawable != null) {
130            dwidth = mDrawable.getIntrinsicWidth();
131            dheight = mDrawable.getIntrinsicHeight();
132            mDrawable.setBounds(0, 0, dwidth, dheight);
133            vwidth -= 2 * (mFrameWidth - 1);
134            vheight -= 2 * (mFrameWidth - 1);
135        } else {
136            return;
137        }
138
139        float scale;
140        float dx;
141        float dy;
142
143        scale = Math.min((float) vwidth / (float) dwidth,
144                (float) vheight / (float) dheight);
145
146        dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
147        dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
148
149        mDrawMatrix.setScale(scale, scale);
150        mDrawMatrix.postTranslate(dx, dy);
151        mScale = scale;
152    }
153
154    @Override
155    protected void onDraw(Canvas canvas) {
156        int frameColor = isActivated() ? mActiveFrameColor : mFrameColor;
157        float halfW = getWidth() / 2f;
158        float halfH = getHeight() / 2f;
159        float halfSW = Math.min(halfH, halfW);
160        if (mBitmap != null && mScale > 0) {
161            int saveCount = canvas.getSaveCount();
162            canvas.save();
163            canvas.translate(mPaddingLeft, mPaddingTop);
164            canvas.concat(mDrawMatrix);
165            float halfBW = mBitmap.getWidth() / 2f;
166            float halfBH = mBitmap.getHeight() / 2f;
167            float halfBSW = Math.min(halfBH, halfBW);
168            canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint);
169            canvas.restoreToCount(saveCount);
170        } else if (mDrawable != null && mScale > 0) {
171            int saveCount = canvas.getSaveCount();
172            canvas.save();
173            canvas.translate(mPaddingLeft, mPaddingTop);
174            canvas.translate(mFrameWidth - 1, mFrameWidth - 1);
175            canvas.concat(mDrawMatrix);
176            mDrawable.draw(canvas);
177            canvas.restoreToCount(saveCount);
178        }
179        if (frameColor != 0) {
180            mFramePaint.setColor(frameColor);
181            mFramePaint.setStrokeWidth(mFrameWidth);
182            canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
183        }
184    }
185
186    public void setDrawable(Drawable d) {
187        if (mDrawable != null) {
188            mDrawable.setCallback(null);
189            unscheduleDrawable(mDrawable);
190        }
191        mDrawable = d;
192        if (d != null) {
193            d.setCallback(this);
194            if (d.isStateful()) {
195                d.setState(getDrawableState());
196            }
197            d.setLayoutDirection(getLayoutDirection());
198            configureBounds();
199        }
200        if (d != null) {
201            mBitmap = null;
202        }
203        configureBounds();
204        invalidate();
205    }
206
207    @Override
208    public void invalidateDrawable(Drawable dr) {
209        if (dr == mDrawable) {
210            invalidate();
211        } else {
212            super.invalidateDrawable(dr);
213        }
214    }
215}
216