CircleTimerView.java revision 113e1daddd8cb0e890084aa4b6ea3194d8ad4826
1package com.android.deskclock;
2
3import android.content.Context;
4import android.content.SharedPreferences;
5import android.content.res.Configuration;
6import android.content.res.Resources;
7import android.graphics.Canvas;
8import android.graphics.Color;
9import android.graphics.Paint;
10import android.graphics.RectF;
11import android.graphics.Typeface;
12import android.os.Parcel;
13import android.os.Parcelable;
14import android.util.AttributeSet;
15import android.view.View;
16
17import com.android.deskclock.stopwatch.Stopwatches;
18
19/**
20 * TODO: Insert description here. (generated by isaackatz)
21 */
22public class CircleTimerView extends View {
23
24
25    private int mRedColor;
26    private int mWhiteColor;
27    private long mIntervalTime = 0;
28    private long mIntervalStartTime = -1;
29    private long mMarkerTime = -1;
30    private long mCurrentIntervalTime = 0;
31    private long mAccumulatedTime = 0;
32    private boolean mPaused = false;
33    private static float mStrokeSize = 4;
34    private static float mDiamondStrokeSize = 12;
35    private static float mMarkerStrokeSize = 2;
36    private final Paint mPaint = new Paint();
37    private final RectF mArcRect = new RectF();
38    private Resources mResources;
39    private float mRadiusOffset;   // amount to remove from radius to account for markers on circle
40
41    // Class has 2 modes:
42    // Timer mode - counting down. in this mode the animation is counter-clockwise and stops at 0
43    // Stop watch mode - counting up - in this mode the animation is clockwise and will keep the
44    //                   animation until stopped.
45    private boolean mTimerMode = false; // default is stop watch view
46
47    Runnable mAnimationThread = new Runnable() {
48
49        @Override
50        public void run() {
51            mCurrentIntervalTime =
52                    Utils.getTimeNow() - mIntervalStartTime + mAccumulatedTime;
53            invalidate();
54            postDelayed(mAnimationThread, 20);
55        }
56
57    };
58
59    public CircleTimerView(Context context) {
60        this(context, null);
61    }
62
63    public CircleTimerView(Context context, AttributeSet attrs) {
64        super(context, attrs);
65        init(context);
66    }
67
68    public void setIntervalTime(long t) {
69        mIntervalTime = t;
70        postInvalidate();
71    }
72
73    public void setMarkerTime(long t) {
74        mMarkerTime = t;
75        postInvalidate();
76    }
77
78    public void reset() {
79        mIntervalStartTime = -1;
80        mMarkerTime = -1;
81        postInvalidate();
82    }
83    public void startIntervalAnimation() {
84        mIntervalStartTime = Utils.getTimeNow();
85        this.post(mAnimationThread);
86        mPaused = false;
87    }
88    public void stopIntervalAnimation() {
89        this.removeCallbacks(mAnimationThread);
90        mIntervalStartTime = -1;
91        mAccumulatedTime = 0;
92    }
93
94    public boolean isAnimating() {
95        return (mIntervalStartTime != -1);
96    }
97
98    public void pauseIntervalAnimation() {
99        this.removeCallbacks(mAnimationThread);
100        mAccumulatedTime += Utils.getTimeNow() - mIntervalStartTime;
101        mPaused = true;
102    }
103
104    public void setPassedTime(long time) {
105        mAccumulatedTime = time;
106        postInvalidate();
107    }
108
109
110
111    private void init(Context c) {
112
113        mResources = c.getResources();
114        mStrokeSize = mResources.getDimension(R.dimen.circletimer_circle_size);
115        mDiamondStrokeSize = mResources.getDimension(R.dimen.circletimer_diamond_size);
116        mMarkerStrokeSize =
117                mResources.getDimension(R.dimen.circletimer_marker_size) * 2 + mStrokeSize;
118        mPaint.setAntiAlias(true);
119        mPaint.setStyle(Paint.Style.STROKE);
120        mWhiteColor = mResources.getColor(R.color.clock_white);
121        mRedColor = mResources.getColor(R.color.clock_red);
122
123        mRadiusOffset = Math.max(mStrokeSize, Math.max(mDiamondStrokeSize, mMarkerStrokeSize));
124    }
125
126    public void setTimerMode(boolean mode) {
127        mTimerMode = mode;
128    }
129
130    @Override
131    public void onDraw(Canvas canvas) {
132        int xCenter = getWidth() / 2 + 1;
133        int yCenter = getHeight() / 2;
134
135        mPaint.setStrokeWidth(mStrokeSize);
136        float radius = Math.min(xCenter, yCenter) - mRadiusOffset;
137
138        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
139            xCenter = (int) (radius + mRadiusOffset);
140        }
141
142        if (mIntervalStartTime == -1) {
143            // just draw a complete white circle, no red arc needed
144            mPaint.setColor(mWhiteColor);
145            canvas.drawCircle (xCenter, yCenter, radius, mPaint);
146        } else {
147            //draw a combination of red and white arcs to create a circle
148            mArcRect.top = yCenter - radius;
149            mArcRect.bottom = yCenter + radius;
150            mArcRect.left =  xCenter - radius;
151            mArcRect.right = xCenter + radius;
152            float redPercent = (float)mCurrentIntervalTime / (float)mIntervalTime;
153            // prevent timer from doing more than one full circle
154            redPercent = (redPercent > 1 && mTimerMode) ? 1 : redPercent;
155
156            float whitePercent = 1 - (redPercent > 1 ? 1 : redPercent);
157            // draw red arc here
158            mPaint.setColor(mRedColor);
159            if (mTimerMode){
160                canvas.drawArc (mArcRect, 270, - redPercent * 360 , false, mPaint);
161            } else {
162                canvas.drawArc (mArcRect, 270, + redPercent * 360 , false, mPaint);
163            }
164
165            // draw white arc here
166            mPaint.setStrokeWidth(mStrokeSize);
167            mPaint.setColor(mWhiteColor);
168            if (mTimerMode) {
169                canvas.drawArc(mArcRect, 270, + whitePercent * 360, false, mPaint);
170            } else {
171                canvas.drawArc(mArcRect, 270 + (1 - whitePercent) * 360,
172                        whitePercent * 360, false, mPaint);
173            }
174
175            // draw red diamond here
176            mPaint.setColor(mRedColor);
177            mPaint.setStrokeWidth(mDiamondStrokeSize);
178            if (mTimerMode){
179                canvas.drawArc (mArcRect, 265 - redPercent * 360, 10 , false, mPaint);
180            } else {
181                canvas.drawArc (mArcRect, 265 + redPercent * 360, 10 , false, mPaint);
182            }
183
184
185         }
186        if (mMarkerTime != -1) {
187            mPaint.setStrokeWidth(mMarkerStrokeSize);
188            mPaint.setColor(mWhiteColor);
189            float angle = (float)(mMarkerTime % mIntervalTime) / (float)mIntervalTime * 360;
190            canvas.drawArc (mArcRect, 270 + angle, 1 , false, mPaint);
191        }
192    }
193
194    public static final String PREF_CTV_PAUSED  = "_ctv_paused";
195    public static final String PREF_CTV_INTERVAL  = "_ctv_interval";
196    public static final String PREF_CTV_INTERVAL_START = "_ctv_interval_start";
197    public static final String PREF_CTV_CURRENT_INTERVAL = "_ctv_current_interval";
198    public static final String PREF_CTV_ACCUM_TIME = "_ctv_accum_time";
199    public static final String PREF_CTV_TIMER_MODE = "_ctv_timer_mode";
200    public static final String PREF_CTV_MARKER_TIME = "_ctv_marker_time";
201
202    // Since this view is used in multiple places, use the key to save different instances
203    public void writeToSharedPref(SharedPreferences prefs, String key) {
204        SharedPreferences.Editor editor = prefs.edit();
205        editor.putBoolean (key + PREF_CTV_PAUSED, mPaused);
206        editor.putLong (key + PREF_CTV_INTERVAL, mIntervalTime);
207        editor.putLong (key + PREF_CTV_INTERVAL_START, mIntervalStartTime);
208        editor.putLong (key + PREF_CTV_CURRENT_INTERVAL, mCurrentIntervalTime);
209        editor.putLong (key + PREF_CTV_ACCUM_TIME, mAccumulatedTime);
210        editor.putLong (key + PREF_CTV_MARKER_TIME, mMarkerTime);
211        editor.putBoolean (key + PREF_CTV_TIMER_MODE, mTimerMode);
212        editor.apply();
213    }
214
215    public void readFromSharedPref(SharedPreferences prefs, String key) {
216        mPaused = prefs.getBoolean(key + PREF_CTV_PAUSED, false);
217        mIntervalTime = prefs.getLong(key + PREF_CTV_INTERVAL, 0);
218        mIntervalStartTime = prefs.getLong(key + PREF_CTV_INTERVAL_START, -1);
219        mCurrentIntervalTime = prefs.getLong(key + PREF_CTV_CURRENT_INTERVAL, 0);
220        mAccumulatedTime = prefs.getLong(key + PREF_CTV_ACCUM_TIME, 0);
221        mMarkerTime = prefs.getLong(key + PREF_CTV_MARKER_TIME, -1);
222        mTimerMode = prefs.getBoolean(key + PREF_CTV_TIMER_MODE, false);
223        if (mIntervalStartTime != -1 && !mPaused) {
224            this.post(mAnimationThread);
225        }
226    }
227
228    public void clearSharedPref(SharedPreferences prefs, String key) {
229        SharedPreferences.Editor editor = prefs.edit();
230        editor.remove (Stopwatches.PREF_START_TIME);
231        editor.remove (Stopwatches.PREF_ACCUM_TIME);
232        editor.remove (Stopwatches.PREF_STATE);
233        editor.remove (key + PREF_CTV_PAUSED);
234        editor.remove (key + PREF_CTV_INTERVAL);
235        editor.remove (key + PREF_CTV_INTERVAL_START);
236        editor.remove (key + PREF_CTV_CURRENT_INTERVAL);
237        editor.remove (key + PREF_CTV_ACCUM_TIME);
238        editor.remove (key + PREF_CTV_MARKER_TIME);
239        editor.remove (key + PREF_CTV_TIMER_MODE);
240        editor.apply();
241    }
242}
243