196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk/*
296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * Copyright (C) 2016 The Android Open Source Project
396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk *
496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * except in compliance with the License. You may obtain a copy of the License at
696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk *
796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk *
996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
1096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * KIND, either express or implied. See the License for the specific language governing
1296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk * permissions and limitations under the License.
1396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk */
1496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
1596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkpackage com.android.settingslib.graph;
1696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
1796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.annotation.Nullable;
1896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.content.Context;
1996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.content.res.Resources;
2096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Canvas;
2196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.CornerPathEffect;
2296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.DashPathEffect;
2396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.LinearGradient;
2496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Paint;
2596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Paint.Cap;
2696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Paint.Join;
2796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Paint.Style;
2896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Path;
2996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.Shader.TileMode;
3096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.graphics.drawable.Drawable;
3196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.util.AttributeSet;
3296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.util.SparseIntArray;
3396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.util.TypedValue;
3496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport android.view.View;
3596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkimport com.android.settingslib.R;
3696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
3796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monkpublic class UsageGraph extends View {
3896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
3996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private static final int PATH_DELIM = -1;
4096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
4196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final Paint mLinePaint;
4296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final Paint mFillPaint;
4396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final Paint mDottedPaint;
4496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
4596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final Drawable mDivider;
460193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private final Drawable mTintedDivider;
4796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final int mDividerSize;
4896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
4996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final Path mPath = new Path();
5096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
5196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    // Paths in coordinates they are passed in.
5296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final SparseIntArray mPaths = new SparseIntArray();
5396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    // Paths in local coordinates for drawing.
5496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private final SparseIntArray mLocalPaths = new SparseIntArray();
550193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private final int mCornerRadius;
5696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
5796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private int mAccentColor;
5896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private boolean mShowProjection;
5996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private boolean mProjectUp;
6096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
6196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private float mMaxX = 100;
6296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private float mMaxY = 100;
6396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
640193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private float mMiddleDividerLoc = .5f;
650193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private int mMiddleDividerTint = -1;
660193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private int mTopDividerTint = -1;
670193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk
6896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    public UsageGraph(Context context, @Nullable AttributeSet attrs) {
6996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        super(context, attrs);
7096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        final Resources resources = context.getResources();
7196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
7296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint = new Paint();
7396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setStyle(Style.STROKE);
7496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setStrokeCap(Cap.ROUND);
7596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setStrokeJoin(Join.ROUND);
7696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setAntiAlias(true);
770193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mCornerRadius = resources.getDimensionPixelSize(R.dimen.usage_graph_line_corner_radius);
780193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mLinePaint.setPathEffect(new CornerPathEffect(mCornerRadius));
7996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width));
8096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
8196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mFillPaint = new Paint(mLinePaint);
8296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mFillPaint.setStyle(Style.FILL);
8396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
8496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDottedPaint = new Paint(mLinePaint);
8596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDottedPaint.setStyle(Style.STROKE);
8696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size);
8796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval);
8896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDottedPaint.setStrokeWidth(dots * 3);
8996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDottedPaint.setPathEffect(new DashPathEffect(new float[] {dots, interval}, 0));
9096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots));
9196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
9296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        TypedValue v = new TypedValue();
9396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true);
9496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDivider = context.getDrawable(v.resourceId);
950193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mTintedDivider = context.getDrawable(v.resourceId);
9696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size);
9796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
9896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
9996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    void clearPaths() {
10096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPaths.clear();
10196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
10296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
10396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    void setMax(int maxX, int maxY) {
10496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mMaxX = maxX;
10596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mMaxY = maxY;
10696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
10796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
1080193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    void setDividerLoc(int height) {
1090193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mMiddleDividerLoc = 1 - height / mMaxY;
1100193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    }
1110193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk
1120193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    void setDividerColors(int middleColor, int topColor) {
1130193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mMiddleDividerTint = middleColor;
1140193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        mTopDividerTint = topColor;
1150193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    }
1160193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk
11796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    public void addPath(SparseIntArray points) {
11896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        for (int i = 0; i < points.size(); i++) {
11996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            mPaths.put(points.keyAt(i), points.valueAt(i));
12096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
12196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPaths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM);
12296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        calculateLocalPaths();
12396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        postInvalidate();
12496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
12596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
12696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    void setAccentColor(int color) {
12796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mAccentColor = color;
12896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLinePaint.setColor(mAccentColor);
12996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        updateGradient();
13096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        postInvalidate();
13196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
13296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
13396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    void setShowProjection(boolean showProjection, boolean projectUp) {
13496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mShowProjection = showProjection;
13596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mProjectUp = projectUp;
13696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        postInvalidate();
13796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
13896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
13996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    @Override
14096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
14196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        super.onSizeChanged(w, h, oldw, oldh);
14296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        updateGradient();
14396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        calculateLocalPaths();
14496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
14596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
14696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private void calculateLocalPaths() {
14796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        if (getWidth() == 0) return;
14896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mLocalPaths.clear();
14996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        int pendingXLoc = 0;
15096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        int pendingYLoc = PATH_DELIM;
15196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        for (int i = 0; i < mPaths.size(); i++) {
15296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int x = mPaths.keyAt(i);
15396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int y = mPaths.valueAt(i);
15496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            if (y == PATH_DELIM) {
15596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                if (i == mPaths.size() - 1 && pendingYLoc != PATH_DELIM) {
15696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    // Connect to the end of the graph.
15796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    mLocalPaths.put(pendingXLoc, pendingYLoc);
15896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                }
15996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                // Clear out any pending points.
16096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                pendingYLoc = PATH_DELIM;
16196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mLocalPaths.put(pendingXLoc + 1, PATH_DELIM);
16296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            } else {
16396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                final int lx = getX(x);
16496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                final int ly = getY(y);
16596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                pendingXLoc = lx;
16696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                if (mLocalPaths.size() > 0) {
16796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
16896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
1690193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk                    if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
17096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                        pendingYLoc = ly;
17196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                        continue;
17296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    }
17396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                }
17496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mLocalPaths.put(lx, ly);
17596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            }
17696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
17796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
17896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
1790193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private boolean hasDiff(int x1, int x2) {
1800193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        return Math.abs(x2 - x1) >= mCornerRadius;
1810193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    }
1820193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk
18396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private int getX(float x) {
18496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        return (int) (x / mMaxX * getWidth());
18596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
18696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
18796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private int getY(float y) {
18896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        return (int) (getHeight() * (1 - (y / mMaxY)));
18996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
19096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
19196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private void updateGradient() {
19296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mFillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(),
19396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                getColor(mAccentColor, .2f), 0, TileMode.CLAMP));
19496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
19596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
19696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private int getColor(int color, float alphaScale) {
19796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        return (color & (((int) (0xff * alphaScale) << 24) | 0xffffff));
19896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
19996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
20096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    @Override
20196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    protected void onDraw(Canvas canvas) {
20296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        // Draw lines across the top, middle, and bottom.
2030193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        if (mMiddleDividerLoc != 0) {
2040193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk            drawDivider(0, canvas, mTopDividerTint);
2050193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        }
2060193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        drawDivider((int) ((canvas.getHeight() - mDividerSize) * mMiddleDividerLoc), canvas,
2070193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk                mMiddleDividerTint);
2080193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
20996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
21096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        if (mLocalPaths.size() == 0) {
21196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            return;
21296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
21396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        if (mShowProjection) {
21496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            drawProjection(canvas);
21596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
21696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        drawFilledPath(canvas);
21796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        drawLinePath(canvas);
21896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
21996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
22096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private void drawProjection(Canvas canvas) {
22196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.reset();
22296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        int x = mLocalPaths.keyAt(mLocalPaths.size() - 2);
22396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        int y = mLocalPaths.valueAt(mLocalPaths.size() - 2);
22496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.moveTo(x, y);
22596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.lineTo(canvas.getWidth(), mProjectUp ? 0 : canvas.getHeight());
22696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        canvas.drawPath(mPath, mDottedPaint);
22796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
22896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
22996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private void drawLinePath(Canvas canvas) {
23096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.reset();
23196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
23296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        for (int i = 1; i < mLocalPaths.size(); i++) {
23396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int x = mLocalPaths.keyAt(i);
23496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int y = mLocalPaths.valueAt(i);
23596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            if (y == PATH_DELIM) {
23696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                if (++i < mLocalPaths.size()) {
23796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
23896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                }
23996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            } else {
24096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mPath.lineTo(x, y);
24196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            }
24296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
24396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        canvas.drawPath(mPath, mLinePaint);
24496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
24596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
24696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    private void drawFilledPath(Canvas canvas) {
24796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.reset();
24896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        float lastStartX = mLocalPaths.keyAt(0);
24996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
25096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        for (int i = 1; i < mLocalPaths.size(); i++) {
25196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int x = mLocalPaths.keyAt(i);
25296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            int y = mLocalPaths.valueAt(i);
25396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            if (y == PATH_DELIM) {
25496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mPath.lineTo(mLocalPaths.keyAt(i - 1), getHeight());
25596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mPath.lineTo(lastStartX, getHeight());
25696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mPath.close();
25796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                if (++i < mLocalPaths.size()) {
25896ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    lastStartX = mLocalPaths.keyAt(i);
25996ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                    mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
26096ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                }
26196ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            } else {
26296ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk                mPath.lineTo(x, y);
26396ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk            }
26496ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        }
26596ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk        canvas.drawPath(mPath, mFillPaint);
26696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
26796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk
2680193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk    private void drawDivider(int y, Canvas canvas, int tintColor) {
2690193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        Drawable d = mDivider;
2700193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        if (tintColor != -1) {
2710193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk            mTintedDivider.setTint(tintColor);
2720193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk            d = mTintedDivider;
2730193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        }
2740193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        d.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
2750193a87196f5c027b82285e711d8a13e41e4c7d8Jason Monk        d.draw(canvas);
27696ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk    }
27796ab63640f186dd7f983b35f2c4e1a95436e5052Jason Monk}
278