CaretDrawable.java revision 54ba601a99cd8cecc2750e305275c40ac2bfba8b
1/*
2 * Copyright (C) 2016 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 */
16package com.android.launcher3.pageindicators;
17
18import android.content.Context;
19import android.content.res.Resources;
20import android.graphics.Canvas;
21import android.graphics.ColorFilter;
22import android.graphics.Paint;
23import android.graphics.Path;
24import android.graphics.PixelFormat;
25import android.graphics.drawable.Drawable;
26
27import com.android.launcher3.R;
28import com.android.launcher3.util.Themes;
29
30public class CaretDrawable extends Drawable {
31    public static final float PROGRESS_CARET_POINTING_UP = -1f;
32    public static final float PROGRESS_CARET_POINTING_DOWN = 1f;
33    public static final float PROGRESS_CARET_NEUTRAL = 0;
34
35    private float mCaretProgress = PROGRESS_CARET_NEUTRAL;
36
37    private Paint mShadowPaint = new Paint();
38    private Paint mCaretPaint = new Paint();
39    private Path mPath = new Path();
40    private final int mCaretSizePx;
41    private final boolean mUseShadow;
42
43    public CaretDrawable(Context context) {
44        final Resources res = context.getResources();
45
46        final int strokeWidth = res.getDimensionPixelSize(R.dimen.all_apps_caret_stroke_width);
47        final int shadowSpread = res.getDimensionPixelSize(R.dimen.all_apps_caret_shadow_spread);
48
49        mCaretPaint.setColor(Themes.getAttrColor(context, R.attr.workspaceTextColor));
50        mCaretPaint.setAntiAlias(true);
51        mCaretPaint.setStrokeWidth(strokeWidth);
52        mCaretPaint.setStyle(Paint.Style.STROKE);
53        mCaretPaint.setStrokeCap(Paint.Cap.ROUND);
54        mCaretPaint.setStrokeJoin(Paint.Join.ROUND);
55
56        mShadowPaint.setColor(res.getColor(R.color.default_shadow_color_no_alpha));
57        mShadowPaint.setAlpha(Themes.getAlpha(context, android.R.attr.spotShadowAlpha));
58        mShadowPaint.setAntiAlias(true);
59        mShadowPaint.setStrokeWidth(strokeWidth + (shadowSpread * 2));
60        mShadowPaint.setStyle(Paint.Style.STROKE);
61        mShadowPaint.setStrokeCap(Paint.Cap.ROUND);
62        mShadowPaint.setStrokeJoin(Paint.Join.ROUND);
63
64        mUseShadow = !Themes.getAttrBoolean(context, R.attr.isWorkspaceDarkText);
65        mCaretSizePx = res.getDimensionPixelSize(R.dimen.all_apps_caret_size);
66    }
67
68    @Override
69    public int getIntrinsicHeight() {
70        return mCaretSizePx;
71    }
72
73    @Override
74    public int getIntrinsicWidth() {
75        return mCaretSizePx;
76    }
77
78    @Override
79    public void draw(Canvas canvas) {
80        // Assumes caret paint is more important than shadow paint
81        if (Float.compare(mCaretPaint.getAlpha(), 0f) == 0) {
82            return;
83        }
84
85        // Assumes shadow stroke width is larger
86        final float width = getBounds().width() - mShadowPaint.getStrokeWidth();
87        final float height = getBounds().height() - mShadowPaint.getStrokeWidth();
88        final float left = getBounds().left + (mShadowPaint.getStrokeWidth() / 2);
89        final float top = getBounds().top + (mShadowPaint.getStrokeWidth() / 2);
90
91        // When the bounds are square, this will result in a caret with a right angle
92        final float verticalInset = (height / 4);
93        final float caretHeight = (height - (verticalInset * 2));
94
95        mPath.reset();
96        mPath.moveTo(left, top + caretHeight * (1 - getNormalizedCaretProgress()));
97        mPath.lineTo(left + (width / 2), top + caretHeight * getNormalizedCaretProgress());
98        mPath.lineTo(left + width, top + caretHeight * (1 - getNormalizedCaretProgress()));
99        if (mUseShadow) {
100            canvas.drawPath(mPath, mShadowPaint);
101        }
102        canvas.drawPath(mPath, mCaretPaint);
103    }
104
105    /**
106     * Sets the caret progress
107     *
108     * @param progress The progress ({@value #PROGRESS_CARET_POINTING_UP} for pointing up,
109     * {@value #PROGRESS_CARET_POINTING_DOWN} for pointing down, {@value #PROGRESS_CARET_NEUTRAL}
110     * for neutral)
111     */
112    public void setCaretProgress(float progress) {
113        mCaretProgress = progress;
114        invalidateSelf();
115    }
116
117    /**
118     * Returns the caret progress
119     *
120     * @return The progress
121     */
122    public float getCaretProgress() {
123        return mCaretProgress;
124    }
125
126    /**
127     * Returns the caret progress normalized to [0..1]
128     *
129     * @return The normalized progress
130     */
131    public float getNormalizedCaretProgress() {
132        return (mCaretProgress - PROGRESS_CARET_POINTING_UP) /
133                (PROGRESS_CARET_POINTING_DOWN - PROGRESS_CARET_POINTING_UP);
134    }
135
136    @Override
137    public int getOpacity() {
138        return PixelFormat.TRANSLUCENT;
139    }
140
141    @Override
142    public void setAlpha(int alpha) {
143        mCaretPaint.setAlpha(alpha);
144        mShadowPaint.setAlpha(alpha);
145        invalidateSelf();
146    }
147
148    @Override
149    public void setColorFilter(ColorFilter cf) {
150        // no-op
151    }
152}
153