1/**
2 *
3 */
4package com.android.settings.applications;
5
6import android.content.Context;
7import android.graphics.Canvas;
8import android.graphics.LinearGradient;
9import android.graphics.Paint;
10import android.graphics.Path;
11import android.graphics.Rect;
12import android.graphics.Shader;
13import android.util.AttributeSet;
14import android.util.DisplayMetrics;
15import android.view.MotionEvent;
16import android.widget.LinearLayout;
17
18public class LinearColorBar extends LinearLayout {
19    static final int LEFT_COLOR = 0xff009688;
20    static final int MIDDLE_COLOR = 0xff009688;
21    static final int RIGHT_COLOR = 0xffced7db;
22    static final int GRAY_COLOR = 0xff555555;
23    static final int WHITE_COLOR = 0xffffffff;
24
25    private float mRedRatio;
26    private float mYellowRatio;
27    private float mGreenRatio;
28
29    private int mLeftColor = LEFT_COLOR;
30    private int mMiddleColor = MIDDLE_COLOR;
31    private int mRightColor = RIGHT_COLOR;
32
33    private boolean mShowIndicator = true;
34    private boolean mShowingGreen;
35
36    private OnRegionTappedListener mOnRegionTappedListener;
37    private int mColoredRegions = REGION_RED | REGION_YELLOW | REGION_GREEN;
38
39    final Rect mRect = new Rect();
40    final Paint mPaint = new Paint();
41
42    int mLastInterestingLeft, mLastInterestingRight;
43    int mLineWidth;
44
45    int mLastLeftDiv, mLastRightDiv;
46    int mLastRegion;
47
48    final Path mColorPath = new Path();
49    final Path mEdgePath = new Path();
50    final Paint mColorGradientPaint = new Paint();
51    final Paint mEdgeGradientPaint = new Paint();
52
53    public static final int REGION_RED = 1<<0;
54    public static final int REGION_YELLOW = 1<<1;
55    public static final int REGION_GREEN = 1<<2;
56    public static final int REGION_ALL = REGION_RED | REGION_YELLOW | REGION_GREEN;
57
58    public interface OnRegionTappedListener {
59        public void onRegionTapped(int region);
60    }
61
62    public LinearColorBar(Context context, AttributeSet attrs) {
63        super(context, attrs);
64        setWillNotDraw(false);
65        mPaint.setStyle(Paint.Style.FILL);
66        mColorGradientPaint.setStyle(Paint.Style.FILL);
67        mColorGradientPaint.setAntiAlias(true);
68        mEdgeGradientPaint.setStyle(Paint.Style.STROKE);
69        mLineWidth = getResources().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_HIGH
70                ? 2 : 1;
71        mEdgeGradientPaint.setStrokeWidth(mLineWidth);
72        mEdgeGradientPaint.setAntiAlias(true);
73
74    }
75
76    public void setOnRegionTappedListener(OnRegionTappedListener listener) {
77        if (listener != mOnRegionTappedListener) {
78            mOnRegionTappedListener = listener;
79            setClickable(listener != null);
80        }
81    }
82
83    public void setColoredRegions(int regions) {
84        mColoredRegions = regions;
85        invalidate();
86    }
87
88    public void setRatios(float red, float yellow, float green) {
89        mRedRatio = red;
90        mYellowRatio = yellow;
91        mGreenRatio = green;
92        invalidate();
93    }
94
95    public void setColors(int red, int yellow, int green) {
96        mLeftColor = red;
97        mMiddleColor = yellow;
98        mRightColor = green;
99        updateIndicator();
100        invalidate();
101    }
102
103    public void setShowIndicator(boolean showIndicator) {
104        mShowIndicator = showIndicator;
105        updateIndicator();
106        invalidate();
107    }
108
109    public void setShowingGreen(boolean showingGreen) {
110        if (mShowingGreen != showingGreen) {
111            mShowingGreen = showingGreen;
112            updateIndicator();
113            invalidate();
114        }
115    }
116
117    private void updateIndicator() {
118        int off = getPaddingTop() - getPaddingBottom();
119        if (off < 0) off = 0;
120        mRect.top = off;
121        mRect.bottom = getHeight();
122        if (!mShowIndicator) {
123            return;
124        }
125        if (mShowingGreen) {
126            mColorGradientPaint.setShader(new LinearGradient(
127                    0, 0, 0, off-2, mRightColor &0xffffff, mRightColor, Shader.TileMode.CLAMP));
128        } else {
129            mColorGradientPaint.setShader(new LinearGradient(
130                    0, 0, 0, off-2, mMiddleColor&0xffffff, mMiddleColor, Shader.TileMode.CLAMP));
131        }
132        mEdgeGradientPaint.setShader(new LinearGradient(
133                0, 0, 0, off/2, 0x00a0a0a0, 0xffa0a0a0, Shader.TileMode.CLAMP));
134    }
135
136    @Override
137    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
138        super.onSizeChanged(w, h, oldw, oldh);
139        updateIndicator();
140    }
141
142    @Override
143    public boolean onTouchEvent(MotionEvent event) {
144        if (mOnRegionTappedListener != null) {
145            switch (event.getAction()) {
146                case MotionEvent.ACTION_DOWN: {
147                    final int x = (int) event.getX();
148                    if (x < mLastLeftDiv) {
149                        mLastRegion = REGION_RED;
150                    } else if (x < mLastRightDiv) {
151                        mLastRegion = REGION_YELLOW;
152                    } else {
153                        mLastRegion = REGION_GREEN;
154                    }
155                    invalidate();
156                } break;
157            }
158        }
159        return super.onTouchEvent(event);
160    }
161
162    @Override
163    protected void dispatchSetPressed(boolean pressed) {
164        invalidate();
165    }
166
167    @Override
168    public boolean performClick() {
169        if (mOnRegionTappedListener != null && mLastRegion != 0) {
170            mOnRegionTappedListener.onRegionTapped(mLastRegion);
171            mLastRegion = 0;
172        }
173        return super.performClick();
174    }
175
176    private int pickColor(int color, int region) {
177        if (isPressed() && (mLastRegion&region) != 0) {
178            return WHITE_COLOR;
179        }
180        if ((mColoredRegions&region) == 0) {
181            return GRAY_COLOR;
182        }
183        return color;
184    }
185
186    @Override
187    protected void onDraw(Canvas canvas) {
188        super.onDraw(canvas);
189
190        int width = getWidth();
191
192        int left = 0;
193
194        int right = left + (int)(width*mRedRatio);
195        int right2 = right + (int)(width*mYellowRatio);
196        int right3 = right2 + (int)(width*mGreenRatio);
197
198        int indicatorLeft, indicatorRight;
199        if (mShowingGreen) {
200            indicatorLeft = right2;
201            indicatorRight = right3;
202        } else {
203            indicatorLeft = right;
204            indicatorRight = right2;
205        }
206
207        if (mLastInterestingLeft != indicatorLeft || mLastInterestingRight != indicatorRight) {
208            mColorPath.reset();
209            mEdgePath.reset();
210            if (mShowIndicator && indicatorLeft < indicatorRight) {
211                final int midTopY = mRect.top;
212                final int midBottomY = 0;
213                final int xoff = 2;
214                mColorPath.moveTo(indicatorLeft, mRect.top);
215                mColorPath.cubicTo(indicatorLeft, midBottomY,
216                        -xoff, midTopY,
217                        -xoff, 0);
218                mColorPath.lineTo(width+xoff-1, 0);
219                mColorPath.cubicTo(width+xoff-1, midTopY,
220                        indicatorRight, midBottomY,
221                        indicatorRight, mRect.top);
222                mColorPath.close();
223                final float lineOffset = mLineWidth+.5f;
224                mEdgePath.moveTo(-xoff+lineOffset, 0);
225                mEdgePath.cubicTo(-xoff+lineOffset, midTopY,
226                        indicatorLeft+lineOffset, midBottomY,
227                        indicatorLeft+lineOffset, mRect.top);
228                mEdgePath.moveTo(width+xoff-1-lineOffset, 0);
229                mEdgePath.cubicTo(width+xoff-1-lineOffset, midTopY,
230                        indicatorRight-lineOffset, midBottomY,
231                        indicatorRight-lineOffset, mRect.top);
232            }
233            mLastInterestingLeft = indicatorLeft;
234            mLastInterestingRight = indicatorRight;
235        }
236
237        if (!mEdgePath.isEmpty()) {
238            canvas.drawPath(mEdgePath, mEdgeGradientPaint);
239            canvas.drawPath(mColorPath, mColorGradientPaint);
240        }
241
242        if (left < right) {
243            mRect.left = left;
244            mRect.right = right;
245            mPaint.setColor(pickColor(mLeftColor, REGION_RED));
246            canvas.drawRect(mRect, mPaint);
247            width -= (right-left);
248            left = right;
249        }
250
251        mLastLeftDiv = right;
252        mLastRightDiv = right2;
253
254        right = right2;
255
256        if (left < right) {
257            mRect.left = left;
258            mRect.right = right;
259            mPaint.setColor(pickColor(mMiddleColor, REGION_YELLOW));
260            canvas.drawRect(mRect, mPaint);
261            width -= (right-left);
262            left = right;
263        }
264
265
266        right = left + width;
267        if (left < right) {
268            mRect.left = left;
269            mRect.right = right;
270            mPaint.setColor(pickColor(mRightColor, REGION_GREEN));
271            canvas.drawRect(mRect, mPaint);
272        }
273    }
274}