UserAvatarView.java revision b325ce8203a751b0223e737be1469c42907e6cd5
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        if (mBitmap != null) {
94            mBitmapPaint.setShader(new BitmapShader(
95                    bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
96        } else {
97            mBitmapPaint.setShader(null);
98        }
99        configureBounds();
100        invalidate();
101    }
102
103    public void setFrameColor(int frameColor) {
104        mFrameColor = frameColor;
105        invalidate();
106    }
107
108    public void setActiveFrameColor(int activeFrameColor) {
109        mActiveFrameColor = activeFrameColor;
110        invalidate();
111    }
112
113    public void setFrameWidth(float frameWidth) {
114        mFrameWidth = frameWidth;
115        invalidate();
116    }
117
118    @Override
119    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
120        super.onLayout(changed, left, top, right, bottom);
121        configureBounds();
122    }
123
124    public void configureBounds() {
125        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
126        int vheight = getHeight() - mPaddingTop - mPaddingBottom;
127
128        int dwidth;
129        int dheight;
130        if (mBitmap != null) {
131            dwidth = mBitmap.getWidth();
132            dheight = mBitmap.getHeight();
133        } else if (mDrawable != null) {
134            dwidth = mDrawable.getIntrinsicWidth();
135            dheight = mDrawable.getIntrinsicHeight();
136            mDrawable.setBounds(0, 0, dwidth, dheight);
137            vwidth -= 2 * (mFrameWidth - 1);
138            vheight -= 2 * (mFrameWidth - 1);
139        } else {
140            return;
141        }
142
143        float scale;
144        float dx;
145        float dy;
146
147        scale = Math.min((float) vwidth / (float) dwidth,
148                (float) vheight / (float) dheight);
149
150        dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
151        dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
152
153        mDrawMatrix.setScale(scale, scale);
154        mDrawMatrix.postTranslate(dx, dy);
155        mScale = scale;
156    }
157
158    @Override
159    protected void onDraw(Canvas canvas) {
160        int frameColor = isActivated() ? mActiveFrameColor : mFrameColor;
161        float halfW = getWidth() / 2f;
162        float halfH = getHeight() / 2f;
163        float halfSW = Math.min(halfH, halfW);
164        if (mBitmap != null && mScale > 0) {
165            int saveCount = canvas.getSaveCount();
166            canvas.save();
167            canvas.translate(mPaddingLeft, mPaddingTop);
168            canvas.concat(mDrawMatrix);
169            float halfBW = mBitmap.getWidth() / 2f;
170            float halfBH = mBitmap.getHeight() / 2f;
171            float halfBSW = Math.min(halfBH, halfBW);
172            canvas.drawCircle(halfBW, halfBH, halfBSW - mFrameWidth / mScale + 1, mBitmapPaint);
173            canvas.restoreToCount(saveCount);
174        } else if (mDrawable != null && mScale > 0) {
175            int saveCount = canvas.getSaveCount();
176            canvas.save();
177            canvas.translate(mPaddingLeft, mPaddingTop);
178            canvas.translate(mFrameWidth - 1, mFrameWidth - 1);
179            canvas.concat(mDrawMatrix);
180            mDrawable.draw(canvas);
181            canvas.restoreToCount(saveCount);
182        }
183        if (frameColor != 0) {
184            mFramePaint.setColor(frameColor);
185            mFramePaint.setStrokeWidth(mFrameWidth);
186            canvas.drawCircle(halfW, halfH, halfSW - mFrameWidth / 2f, mFramePaint);
187        }
188    }
189
190    public void setDrawable(Drawable d) {
191        if (mDrawable != null) {
192            mDrawable.setCallback(null);
193            unscheduleDrawable(mDrawable);
194        }
195        mDrawable = d;
196        if (d != null) {
197            d.setCallback(this);
198            if (d.isStateful()) {
199                d.setState(getDrawableState());
200            }
201            d.setLayoutDirection(getLayoutDirection());
202            configureBounds();
203        }
204        if (d != null) {
205            mBitmap = null;
206        }
207        configureBounds();
208        invalidate();
209    }
210
211    @Override
212    public void invalidateDrawable(Drawable dr) {
213        if (dr == mDrawable) {
214            invalidate();
215        } else {
216            super.invalidateDrawable(dr);
217        }
218    }
219}
220