1689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira/*
2689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * Copyright (C) 2014 The Android Open Source Project
3689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira *
4689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
5689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * you may not use this file except in compliance with the License.
6689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * You may obtain a copy of the License at
7689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira *
8689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira *      http://www.apache.org/licenses/LICENSE-2.0
9689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira *
10689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * Unless required by applicable law or agreed to in writing, software
11689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
12689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * See the License for the specific language governing permissions and
14689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * limitations under the License.
15689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira */
16689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
17689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereirapackage android.support.v4.widget;
18689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
19689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.animation.AccelerateDecelerateInterpolator;
20689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.animation.Interpolator;
21689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.animation.Animation;
22689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.animation.LinearInterpolator;
23689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.animation.Transformation;
24689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.content.Context;
25689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.content.res.Resources;
26689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.Canvas;
27689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.Color;
28689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.ColorFilter;
29689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.Paint;
30689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.Paint.Style;
3174437a01478b39230bb5b4657b74480ede53ae94Mindy Pereiraimport android.graphics.Path;
32689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.PixelFormat;
33689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.Rect;
34689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.RectF;
35689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.drawable.Drawable;
36689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.graphics.drawable.Animatable;
37d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereiraimport android.support.annotation.IntDef;
38d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereiraimport android.support.annotation.NonNull;
39689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.util.DisplayMetrics;
40689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport android.view.View;
4174437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
42d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereiraimport java.lang.annotation.Retention;
43d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereiraimport java.lang.annotation.RetentionPolicy;
44689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraimport java.util.ArrayList;
45689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
46689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira/**
47689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira * Fancy progress indicator for Material theme.
48dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira *
49dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira * @hide
50689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira */
51689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereiraclass MaterialProgressDrawable extends Drawable implements Animatable {
52689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
53689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator();
54689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator();
55dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira    private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator();
56689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
57d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    @Retention(RetentionPolicy.CLASS)
58dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira    @IntDef({LARGE, DEFAULT})
59d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    public @interface ProgressDrawableSize {}
60689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    // Maps to ProgressBar.Large style
61689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    static final int LARGE = 0;
62689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    // Maps to ProgressBar default style
63689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    static final int DEFAULT = 1;
64689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
65689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    // Maps to ProgressBar default style
6674437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    private static final int CIRCLE_DIAMETER = 40;
67dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
68dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final float STROKE_WIDTH = 2.5f;
69689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
70689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    // Maps to ProgressBar.Large style
71dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira    private static final int CIRCLE_DIAMETER_LARGE = 56;
72dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final float CENTER_RADIUS_LARGE = 12.5f;
73dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira    private static final float STROKE_WIDTH_LARGE = 3f;
74689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
75689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private final int[] COLORS = new int[] {
76689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        Color.BLACK
77689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    };
78689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
79689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /** The duration of a single progress spin in milliseconds. */
80689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static final int ANIMATION_DURATION = 1000 * 80 / 60;
81689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
82689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /** The number of points in the progress "star". */
83689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static final float NUM_POINTS = 5f;
84689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /** The list of animators operating on this drawable. */
85689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();
86689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
87689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /** The indicator ring, used to manage animation state. */
88689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private final Ring mRing;
89689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
90689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /** Canvas rotation in degrees. */
91689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private float mRotation;
92689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
9374437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    /** Layout info for the arrowhead in dp */
9474437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    private static final int ARROW_WIDTH = 10;
9574437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    private static final int ARROW_HEIGHT = 5;
96dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final float ARROW_OFFSET_ANGLE = 5;
97dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira
98dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira    /** Layout info for the arrowhead for the large spinner in dp */
99dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final int ARROW_WIDTH_LARGE = 12;
100dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final int ARROW_HEIGHT_LARGE = 6;
101dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private static final float MAX_PROGRESS_ARC = .8f;
10274437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
103689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private Resources mResources;
104689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private View mParent;
105689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private Animation mAnimation;
106689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private float mRotationCount;
107689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private double mWidth;
108689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private double mHeight;
109fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira    boolean mFinishing;
110689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
111689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public MaterialProgressDrawable(Context context, View parent) {
112689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mParent = parent;
113689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mResources = context.getResources();
114689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
115689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing = new Ring(mCallback);
116112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        mRing.setColors(COLORS);
117689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
118dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        updateSizes(DEFAULT);
119689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        setupAnimators();
120689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
121689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
122dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
123dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
124689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final Ring ring = mRing;
125689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final DisplayMetrics metrics = mResources.getDisplayMetrics();
126689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final float screenDensity = metrics.density;
127689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
128689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mWidth = progressCircleWidth * screenDensity;
129689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mHeight = progressCircleHeight * screenDensity;
130dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        ring.setStrokeWidth((float) strokeWidth * screenDensity);
131dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        ring.setCenterRadius(centerRadius * screenDensity);
132d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        ring.setColorIndex(0);
133dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
134dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        ring.setInsets((int) mWidth, (int) mHeight);
135689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
136689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
137d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    /**
138d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * Set the overall size for the progress spinner. This updates the radius
139d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * and stroke width of the ring.
140d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     *
141dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira     * @param size One of {@link MaterialProgressDrawable.LARGE} or
142dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira     *            {@link MaterialProgressDrawable.DEFAULT}
143d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     */
144dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    public void updateSizes(@ProgressDrawableSize int size) {
145689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        if (size == LARGE) {
146dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
147dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                    STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
148689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        } else {
149dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
150dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                    ARROW_WIDTH, ARROW_HEIGHT);
151689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
152689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
153689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
154d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    /**
155d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * @param show Set to true to display the arrowhead on the progress spinner.
156d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     */
15774437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    public void showArrow(boolean show) {
15874437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        mRing.setShowArrow(show);
15974437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    }
16074437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
161d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    /**
162d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * @param scale Set the scale of the arrowhead for the spinner.
163d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     */
16474437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    public void setArrowScale(float scale) {
16574437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        mRing.setArrowScale(scale);
16674437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira    }
16774437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
168d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    /**
169d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * Set the start and end trim for the progress spinner arc.
170d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     *
171d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * @param startAngle start angle
172d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * @param endAngle end angle
173d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     */
174d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    public void setStartEndTrim(float startAngle, float endAngle) {
175d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        mRing.setStartTrim(startAngle);
176d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        mRing.setEndTrim(endAngle);
177689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
178689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
179d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    /**
180d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     * Set the amount of rotation to apply to the progress spinner.
181d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     *
182dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira     * @param rotation Rotation is from [0..1]
183d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira     */
184d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira    public void setProgressRotation(float rotation) {
185d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        mRing.setRotation(rotation);
186689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
187689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
188689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /**
189dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira     * Update the background color of the circle image view.
190dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira     */
191dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    public void setBackgroundColor(int color) {
192dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        mRing.setBackgroundColor(color);
193dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira     }
194dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
195dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    /**
196689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * Set the colors used in the progress animation from color resources.
197689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * The first color will also be the color of the bar that grows in response
198689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * to a user swipe gesture.
199689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     *
200689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * @param colors
201689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     */
202689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void setColorSchemeColors(int... colors) {
203112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        mRing.setColors(colors);
204112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        mRing.setColorIndex(0);
205689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
206689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
207689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
208689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public int getIntrinsicHeight() {
209689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return (int) mHeight;
210689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
211689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
212689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
213689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public int getIntrinsicWidth() {
214689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return (int) mWidth;
215689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
216689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
217689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
218689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void draw(Canvas c) {
219689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final Rect bounds = getBounds();
220689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final int saveCount = c.save();
221689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
222689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing.draw(c, bounds);
223689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        c.restoreToCount(saveCount);
224689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
225689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
226689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
227689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void setAlpha(int alpha) {
228689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing.setAlpha(alpha);
229689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
230689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
231689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public int getAlpha() {
232689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return mRing.getAlpha();
233689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
234689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
235689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
236689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void setColorFilter(ColorFilter colorFilter) {
237689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing.setColorFilter(colorFilter);
238689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
239689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
240dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    @SuppressWarnings("unused")
241dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira    void setRotation(float rotation) {
242689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRotation = rotation;
243689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        invalidateSelf();
244689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
245689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
246689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @SuppressWarnings("unused")
247689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private float getRotation() {
248689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return mRotation;
249689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
250689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
251689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
252689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public int getOpacity() {
253689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return PixelFormat.TRANSLUCENT;
254689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
255689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
256689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
257689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public boolean isRunning() {
258689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final ArrayList<Animation> animators = mAnimators;
259689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final int N = animators.size();
260689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        for (int i = 0; i < N; i++) {
261689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            final Animation animator = animators.get(i);
262689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            if (animator.hasStarted() && !animator.hasEnded()) {
263689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira                return true;
264689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            }
265689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
266689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        return false;
267689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
268689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
269689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
270689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void start() {
271689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mAnimation.reset();
272689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing.storeOriginals();
273dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        // Already showing some part of the ring
274dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        if (mRing.getEndTrim() != mRing.getStartTrim()) {
275fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira            mFinishing = true;
276fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira            mAnimation.setDuration(ANIMATION_DURATION/2);
277fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira            mParent.startAnimation(mAnimation);
278689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        } else {
279112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira            mRing.setColorIndex(0);
280689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mRing.resetOriginals();
281fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira            mAnimation.setDuration(ANIMATION_DURATION);
282689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mParent.startAnimation(mAnimation);
283689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
284689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
285689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
286689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    @Override
287689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    public void stop() {
288689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mParent.clearAnimation();
289689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        setRotation(0);
290dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        mRing.setShowArrow(false);
291112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        mRing.setColorIndex(0);
292689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mRing.resetOriginals();
293689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
294689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
295fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira    private void applyFinishTranslation(float interpolatedTime, Ring ring) {
296fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        // shrink back down and complete a full rotation before
297fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        // starting other circles
298fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        // Rotation goes between [0..1].
299fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
300fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                + 1f);
301fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        final float startTrim = ring.getStartingStartTrim()
302fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                + (ring.getStartingEndTrim() - ring.getStartingStartTrim()) * interpolatedTime;
303fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        ring.setStartTrim(startTrim);
304fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        final float rotation = ring.getStartingRotation()
305fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
306fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira        ring.setRotation(rotation);
307fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira    }
308fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira
309689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private void setupAnimators() {
310689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final Ring ring = mRing;
311689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        final Animation animation = new Animation() {
312fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                @Override
313689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            public void applyTransformation(float interpolatedTime, Transformation t) {
314fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                if (mFinishing) {
315fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    applyFinishTranslation(interpolatedTime, ring);
316fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                } else {
317fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // The minProgressArc is calculated from 0 to create an
318fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // angle that
319fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // matches the stroke width.
320fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float minProgressArc = (float) Math.toRadians(
321fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                            ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
322fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float startingEndTrim = ring.getStartingEndTrim();
323fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float startingTrim = ring.getStartingStartTrim();
324fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float startingRotation = ring.getStartingRotation();
325fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira
326fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // Offset the minProgressArc to where the endTrim is
327fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // located.
328fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float minArc = MAX_PROGRESS_ARC - minProgressArc;
329fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float endTrim = startingEndTrim + (minArc
330fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                            * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime));
331fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    ring.setEndTrim(endTrim);
332fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira
333fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float startTrim = startingTrim + (MAX_PROGRESS_ARC
334fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                            * END_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime));
335fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    ring.setStartTrim(startTrim);
336fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira
337fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    final float rotation = startingRotation + (0.25f * interpolatedTime);
338fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    ring.setRotation(rotation);
339fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira
340fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime)
341fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                            + (720.0f * (mRotationCount / NUM_POINTS));
342fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    setRotation(groupRotation);
343fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                }
344689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            }
345689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        };
346689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        animation.setRepeatCount(Animation.INFINITE);
347689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        animation.setRepeatMode(Animation.RESTART);
348689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        animation.setInterpolator(LINEAR_INTERPOLATOR);
349689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        animation.setAnimationListener(new Animation.AnimationListener() {
350689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
351fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                @Override
352689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            public void onAnimationStart(Animation animation) {
353689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira                mRotationCount = 0;
354689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            }
355689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
356fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                @Override
357689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            public void onAnimationEnd(Animation animation) {
358689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira                // do nothing
359689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            }
360689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
361fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                @Override
362689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            public void onAnimationRepeat(Animation animation) {
363dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                ring.storeOriginals();
364112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira                ring.goToNextColor();
365dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                ring.setStartTrim(ring.getEndTrim());
366fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                if (mFinishing) {
367fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // finished closing the last ring from the swipe gesture; go
368fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    // into progress mode
369fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    mFinishing = false;
370fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    animation.setDuration(ANIMATION_DURATION);
371fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    ring.setShowArrow(false);
372fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                } else {
373fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                    mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
374fa77943ee3d8ef33abf4f8288875783de623b4d9Mindy Pereira                }
375689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            }
376689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        });
377689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        mAnimation = animation;
378689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
379689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
380689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private final Callback mCallback = new Callback() {
381689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @Override
382689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void invalidateDrawable(Drawable d) {
383689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
384689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
385689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
386689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @Override
387689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void scheduleDrawable(Drawable d, Runnable what, long when) {
388689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            scheduleSelf(what, when);
389689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
390689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
391689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @Override
392689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void unscheduleDrawable(Drawable d, Runnable what) {
393689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            unscheduleSelf(what);
394689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
395689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    };
396689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
397689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static class Ring {
398689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private final RectF mTempBounds = new RectF();
399689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private final Paint mPaint = new Paint();
40074437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private final Paint mArrowPaint = new Paint();
401689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
402689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private final Callback mCallback;
403689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
404689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStartTrim = 0.0f;
405689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mEndTrim = 0.0f;
406689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mRotation = 0.0f;
407689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStrokeWidth = 5.0f;
408689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStrokeInset = 2.5f;
409689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
410689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private int[] mColors;
411dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        // mColorIndex represents the offset into the available mColors that the
412dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        // progress circle should currently display. As the progress circle is
413dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        // animating, the mColorIndex moves by one to the next available color.
414689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private int mColorIndex;
415689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStartingStartTrim;
416689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStartingEndTrim;
417689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private float mStartingRotation;
41874437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private boolean mShowArrow;
41974437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private Path mArrow;
42074437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private float mArrowScale;
421dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        private double mRingCenterRadius;
42274437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private int mArrowWidth;
42374437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira        private int mArrowHeight;
424dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        private int mAlpha;
425dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        private final Paint mCirclePaint = new Paint();
426dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        private int mBackgroundColor;
427689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
428689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public Ring(Callback callback) {
429689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mCallback = callback;
430689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
4314221e345d86111915467679815ead8888da5e2f4Mindy Pereira            mPaint.setStrokeCap(Paint.Cap.SQUARE);
432689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mPaint.setAntiAlias(true);
433689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mPaint.setStyle(Style.STROKE);
43474437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
435dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            mArrowPaint.setStyle(Paint.Style.FILL);
43674437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira            mArrowPaint.setAntiAlias(true);
437689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
438689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
439dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        public void setBackgroundColor(int color) {
440dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            mBackgroundColor = color;
441dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        }
442dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
443689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        /**
444dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira         * Set the dimensions of the arrowhead.
445dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira         *
446dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira         * @param width Width of the hypotenuse of the arrow head
447dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira         * @param height Height of the arrow point
448dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira         */
449dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        public void setArrowDimensions(float width, float height) {
450dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira            mArrowWidth = (int) width;
451dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira            mArrowHeight = (int) height;
452dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        }
453dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira
454dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira        /**
455d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * Draw the progress spinner
456689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira         */
457689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void draw(Canvas c, Rect bounds) {
458689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            final RectF arcBounds = mTempBounds;
459689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            arcBounds.set(bounds);
460689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            arcBounds.inset(mStrokeInset, mStrokeInset);
461689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
462689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            final float startAngle = (mStartTrim + mRotation) * 360;
463689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            final float endAngle = (mEndTrim + mRotation) * 360;
464689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            float sweepAngle = endAngle - startAngle;
465689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
466689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mPaint.setColor(mColors[mColorIndex]);
467689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
46874437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
469dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            drawTriangle(c, startAngle, sweepAngle, bounds);
470dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
471dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            if (mAlpha < 255) {
472dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mCirclePaint.setColor(mBackgroundColor);
473dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mCirclePaint.setAlpha(255 - mAlpha);
474dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
475dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                        mCirclePaint);
47674437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira            }
477dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        }
47874437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira
479dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
48074437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira            if (mShowArrow) {
481dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                if (mArrow == null) {
482dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                    mArrow = new android.graphics.Path();
483dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                    mArrow.setFillType(android.graphics.Path.FillType.EVEN_ODD);
484dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                } else {
485dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                    mArrow.reset();
48674437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira                }
487dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
488dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // Adjust the position of the triangle so that it is inset as
489dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // much as the arc, but also centered on the arc.
490c39bdbe9d24491caf92194229393ff58c16aed7fMindy Pereira                float inset = (int) mStrokeInset / 2 * mArrowScale;
491dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
492dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());
493dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
494dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // Update the path each time. This works around an issue in SKIA
495dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // where concatenating a rotation matrix to a scale matrix
496dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // ignored a starting negative rotation. This appears to have
497dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // been fixed as of API 21.
498dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mArrow.moveTo(0, 0);
499dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mArrow.lineTo(mArrowWidth * mArrowScale, 0);
500dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
501dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                        * mArrowScale));
502dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mArrow.offset(x - inset, y);
503dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                mArrow.close();
504dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                // draw a triangle
50574437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira                mArrowPaint.setColor(mColors[mColorIndex]);
506dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
507dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                        bounds.exactCenterY());
508dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                c.drawPath(mArrow, mArrowPaint);
50974437a01478b39230bb5b4657b74480ede53ae94Mindy Pereira            }
510689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
511689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
512d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
513d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * Set the colors the progress spinner alternates between.
514d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         *
515d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param colors Array of integers describing the colors. Must be non-<code>null</code>.
516d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
517d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public void setColors(@NonNull int[] colors) {
518689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mColors = colors;
519112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira            // if colors are reset, make sure to reset the color index as well
520112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira            setColorIndex(0);
521689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
522689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
523d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
524d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param index Index into the color array of the color to display in
525d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         *            the progress spinner.
526d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
527689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setColorIndex(int index) {
528689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mColorIndex = index;
529689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
530689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
531112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        /**
532112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira         * Proceed to the next available ring color. This will automatically
533112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira         * wrap back to the beginning of colors.
534112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira         */
535112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        public void goToNextColor() {
536112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira            mColorIndex = (mColorIndex + 1) % (mColors.length);
537112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira        }
538112ae3627e7f32991822b3fd2001fe7239f1d3eaMindy Pereira
539689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setColorFilter(ColorFilter filter) {
540689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mPaint.setColorFilter(filter);
541689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
542689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
543689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
544d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
545d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param alpha Set the alpha of the progress spinner and associated arrowhead.
546d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
547689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setAlpha(int alpha) {
548dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            mAlpha = alpha;
549689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
550689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
551d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
552d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @return Current alpha of the progress spinner and arrowhead.
553d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
554689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public int getAlpha() {
555dc943d6192dab40df68b6b583c84e64045ea1bc8Mindy Pereira            return mAlpha;
556689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
557689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
558d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
559d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param strokeWidth Set the stroke width of the progress spinner in pixels.
560d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
561689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setStrokeWidth(float strokeWidth) {
562689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mStrokeWidth = strokeWidth;
563689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mPaint.setStrokeWidth(strokeWidth);
564689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
565689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
566689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
567689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
568689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getStrokeWidth() {
569689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mStrokeWidth;
570689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
571689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
572689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
573689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setStartTrim(float startTrim) {
574689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mStartTrim = startTrim;
575689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
576689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
577689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
578689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
579689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getStartTrim() {
580689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mStartTrim;
581689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
582689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
583689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getStartingStartTrim() {
584689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mStartingStartTrim;
585689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
586689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
587689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getStartingEndTrim() {
588689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mStartingEndTrim;
589689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
590689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
591689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
592689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setEndTrim(float endTrim) {
593689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mEndTrim = endTrim;
594689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
595689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
596689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
597689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
598689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getEndTrim() {
599689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mEndTrim;
600689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
601689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
602689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
603689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public void setRotation(float rotation) {
604689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mRotation = rotation;
605689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            invalidateSelf();
606689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
607689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
608689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
609689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getRotation() {
610689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mRotation;
611689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
612689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
613dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        public void setInsets(int width, int height) {
614dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            final float minEdge = (float) Math.min(width, height);
615dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            float insets;
616dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            if (mRingCenterRadius <= 0 || minEdge < 0) {
617dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                insets = (float) Math.ceil(mStrokeWidth / 2.0f);
618dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            } else {
619dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira                insets = (float) (minEdge / 2.0f - mRingCenterRadius);
620dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            }
621689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mStrokeInset = insets;
622689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
623689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
624689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @SuppressWarnings("unused")
625689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getInsets() {
626689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return mStrokeInset;
627689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
628689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
629d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
630dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira         * @param centerRadius Inner radius in px of the circle the progress
631d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         *            spinner arc traces.
632d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
633dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        public void setCenterRadius(double centerRadius) {
634dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            mRingCenterRadius = centerRadius;
635dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        }
636dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira
637dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira        public double getCenterRadius() {
638dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira            return mRingCenterRadius;
639d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
640d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
641d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
642d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param show Set to true to show the arrow head on the progress spinner.
643d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
644d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public void setShowArrow(boolean show) {
645d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            if (mShowArrow != show) {
646d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira                mShowArrow = show;
647d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira                invalidateSelf();
648d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            }
649d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
650d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
651d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
652d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * @param scale Set the scale of the arrowhead for the spinner.
653d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
654d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public void setArrowScale(float scale) {
655d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            if (scale != mArrowScale) {
656d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira                mArrowScale = scale;
657d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira                invalidateSelf();
658d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            }
659d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
660d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
661d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
662dd27d55a5152f86c07758067e587bdd5b719abafMindy Pereira         * @return The amount the progress spinner is currently rotated, between [0..1].
663d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
664d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public float getStartingRotation() {
665d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            return mStartingRotation;
666d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
667d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
668d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
669d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * If the start / end trim are offset to begin with, store them so that
670d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * animation starts from that offset.
671d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
672d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public void storeOriginals() {
673d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingStartTrim = mStartTrim;
674d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingEndTrim = mEndTrim;
675d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingRotation = mRotation;
676d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
677d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
678d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        /**
679d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         * Reset the progress spinner to default rotation, start and end angles.
680d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira         */
681d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        public void resetOriginals() {
682d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingStartTrim = 0;
683d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingEndTrim = 0;
684d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            mStartingRotation = 0;
685d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            setStartTrim(0);
686d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            setEndTrim(0);
687d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira            setRotation(0);
688d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira        }
689d08402a890f1ac4d3de832a9a781cbc5ebde804fMindy Pereira
690689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        private void invalidateSelf() {
691689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            mCallback.invalidateDrawable(null);
692689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
693689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
694689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
695689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /**
696689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * Squishes the interpolation curve into the second half of the animation.
697689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     */
698689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static class EndCurveInterpolator extends AccelerateDecelerateInterpolator {
699689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @Override
700689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getInterpolation(float input) {
701689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return super.getInterpolation(Math.max(0, (input - 0.5f) * 2.0f));
702689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
703689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
704689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira
705689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    /**
706689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     * Squishes the interpolation curve into the first half of the animation.
707689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira     */
708689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    private static class StartCurveInterpolator extends AccelerateDecelerateInterpolator {
709689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        @Override
710689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        public float getInterpolation(float input) {
711689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira            return super.getInterpolation(Math.min(1, input * 2.0f));
712689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira        }
713689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira    }
714689ab224266f62aefb35ef0b80af6edf66eb8972Mindy Pereira}
715