1 /*
2  * Copyright (C) 2018 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 package com.android.systemui.bubbles;
17 
18 import android.content.Context;
19 import android.content.res.TypedArray;
20 import android.graphics.Canvas;
21 import android.graphics.Path;
22 import android.graphics.Rect;
23 import android.util.AttributeSet;
24 import android.widget.ImageView;
25 
26 import com.android.internal.graphics.ColorUtils;
27 import com.android.launcher3.icons.DotRenderer;
28 import com.android.systemui.R;
29 
30 /**
31  * View that circle crops its contents and supports displaying a coloured dot on a top corner.
32  */
33 public class BadgedImageView extends ImageView {
34 
35     private Rect mTempBounds = new Rect();
36 
37     private DotRenderer mDotRenderer;
38     private DotRenderer.DrawParams mDrawParams;
39     private int mIconBitmapSize;
40     private int mDotColor;
41     private float mDotScale = 0f;
42     private boolean mShowDot;
43     private boolean mOnLeft;
44 
45     /** Same as value in Launcher3 IconShape */
46     static final int DEFAULT_PATH_SIZE = 100;
47 
BadgedImageView(Context context)48     public BadgedImageView(Context context) {
49         this(context, null);
50     }
51 
BadgedImageView(Context context, AttributeSet attrs)52     public BadgedImageView(Context context, AttributeSet attrs) {
53         this(context, attrs, 0);
54     }
55 
BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr)56     public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
57         this(context, attrs, defStyleAttr, 0);
58     }
59 
BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)60     public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
61             int defStyleRes) {
62         super(context, attrs, defStyleAttr, defStyleRes);
63         mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
64         mDrawParams = new DotRenderer.DrawParams();
65 
66         TypedArray ta = context.obtainStyledAttributes(
67                 new int[]{android.R.attr.colorBackgroundFloating});
68         ta.recycle();
69     }
70 
71     @Override
onDraw(Canvas canvas)72     public void onDraw(Canvas canvas) {
73         super.onDraw(canvas);
74         if (!mShowDot) {
75             return;
76         }
77         getDrawingRect(mTempBounds);
78 
79         mDrawParams.color = mDotColor;
80         mDrawParams.iconBounds = mTempBounds;
81         mDrawParams.leftAlign = mOnLeft;
82         mDrawParams.scale = mDotScale;
83 
84         if (mDotRenderer == null) {
85             Path circlePath = new Path();
86             float radius = DEFAULT_PATH_SIZE * 0.5f;
87             circlePath.addCircle(radius /* x */, radius /* y */, radius, Path.Direction.CW);
88             mDotRenderer = new DotRenderer(mIconBitmapSize, circlePath, DEFAULT_PATH_SIZE);
89         }
90         mDotRenderer.draw(canvas, mDrawParams);
91     }
92 
93     /**
94      * Set whether the dot should appear on left or right side of the view.
95      */
setDotOnLeft(boolean onLeft)96     void setDotOnLeft(boolean onLeft) {
97         mOnLeft = onLeft;
98         invalidate();
99     }
100 
getDotOnLeft()101     boolean getDotOnLeft() {
102         return mOnLeft;
103     }
104 
105     /**
106      * Set whether the dot should show or not.
107      */
setShowDot(boolean showDot)108     void setShowDot(boolean showDot) {
109         mShowDot = showDot;
110         invalidate();
111     }
112 
113     /**
114      * @return whether the dot is being displayed.
115      */
isShowingDot()116     boolean isShowingDot() {
117         return mShowDot;
118     }
119 
120     /**
121      * The colour to use for the dot.
122      */
setDotColor(int color)123     public void setDotColor(int color) {
124         mDotColor = ColorUtils.setAlphaComponent(color, 255 /* alpha */);
125         invalidate();
126     }
127 
128     /**
129      * @param iconPath The new icon path to use when calculating dot position.
130      */
drawDot(Path iconPath)131     public void drawDot(Path iconPath) {
132         mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
133         invalidate();
134     }
135 
136     /**
137      * How big the dot should be, fraction from 0 to 1.
138      */
setDotScale(float fraction)139     void setDotScale(float fraction) {
140         mDotScale = fraction;
141         invalidate();
142     }
143 
144     /**
145      * Return dot position relative to bubble view container bounds.
146      */
getDotCenter()147     float[] getDotCenter() {
148         float[] dotPosition;
149         if (mOnLeft) {
150             dotPosition = mDotRenderer.getLeftDotPosition();
151         } else {
152             dotPosition =  mDotRenderer.getRightDotPosition();
153         }
154         getDrawingRect(mTempBounds);
155         float dotCenterX = mTempBounds.width() * dotPosition[0];
156         float dotCenterY = mTempBounds.height() * dotPosition[1];
157         return new float[]{dotCenterX, dotCenterY};
158     }
159 }
160