Home | History | Annotate | Download | only in timer
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.deskclock.timer;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.graphics.Canvas;
     22 import android.graphics.Color;
     23 import android.graphics.Paint;
     24 import android.graphics.RectF;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 
     28 import com.android.deskclock.R;
     29 import com.android.deskclock.ThemeUtils;
     30 import com.android.deskclock.Utils;
     31 import com.android.deskclock.data.Timer;
     32 
     33 /**
     34  * Custom view that draws timer progress as a circle.
     35  */
     36 public final class TimerCircleView extends View {
     37 
     38     /** The size of the dot indicating the progress through the timer. */
     39     private final float mDotRadius;
     40 
     41     /** An amount to subtract from the true radius to account for drawing thicknesses. */
     42     private final float mRadiusOffset;
     43 
     44     /** The color indicating the remaining portion of the timer. */
     45     private final int mRemainderColor;
     46 
     47     /** The color indicating the completed portion of the timer. */
     48     private final int mCompletedColor;
     49 
     50     /** The size of the stroke that paints the timer circle. */
     51     private final float mStrokeSize;
     52 
     53     private final Paint mPaint = new Paint();
     54     private final Paint mFill = new Paint();
     55     private final RectF mArcRect = new RectF();
     56 
     57     private Timer mTimer;
     58 
     59     @SuppressWarnings("unused")
     60     public TimerCircleView(Context context) {
     61         this(context, null);
     62     }
     63 
     64     public TimerCircleView(Context context, AttributeSet attrs) {
     65         super(context, attrs);
     66 
     67         final Resources resources = context.getResources();
     68         final float dotDiameter = resources.getDimension(R.dimen.circletimer_dot_size);
     69 
     70         mDotRadius = dotDiameter / 2f;
     71         mStrokeSize = resources.getDimension(R.dimen.circletimer_circle_size);
     72         mRadiusOffset = Utils.calculateRadiusOffset(mStrokeSize, dotDiameter, 0);
     73 
     74         mRemainderColor = Color.WHITE;
     75         mCompletedColor = ThemeUtils.resolveColor(context, R.attr.colorAccent);
     76 
     77         mPaint.setAntiAlias(true);
     78         mPaint.setStyle(Paint.Style.STROKE);
     79 
     80         mFill.setAntiAlias(true);
     81         mFill.setColor(mCompletedColor);
     82         mFill.setStyle(Paint.Style.FILL);
     83     }
     84 
     85     void update(Timer timer) {
     86         if (mTimer != timer) {
     87             mTimer = timer;
     88             postInvalidateOnAnimation();
     89         }
     90     }
     91 
     92     @Override
     93     public void onDraw(Canvas canvas) {
     94         if (mTimer == null) {
     95             return;
     96         }
     97 
     98         // Compute the size and location of the circle to be drawn.
     99         final int xCenter = getWidth() / 2;
    100         final int yCenter = getHeight() / 2;
    101         final float radius = Math.min(xCenter, yCenter) - mRadiusOffset;
    102 
    103         // Reset old painting state.
    104         mPaint.setColor(mRemainderColor);
    105         mPaint.setStrokeWidth(mStrokeSize);
    106 
    107         // If the timer is reset, draw a simple white circle.
    108         final float redPercent;
    109         if (mTimer.isReset()) {
    110             // Draw a complete white circle; no red arc required.
    111             canvas.drawCircle(xCenter, yCenter, radius, mPaint);
    112 
    113             // Red percent is 0 since no timer progress has been made.
    114             redPercent = 0;
    115         } else if (mTimer.isExpired()) {
    116             mPaint.setColor(mCompletedColor);
    117 
    118             // Draw a complete white circle; no red arc required.
    119             canvas.drawCircle(xCenter, yCenter, radius, mPaint);
    120 
    121             // Red percent is 1 since the timer has expired.
    122             redPercent = 1;
    123         } else {
    124             // Draw a combination of red and white arcs to create a circle.
    125             mArcRect.top = yCenter - radius;
    126             mArcRect.bottom = yCenter + radius;
    127             mArcRect.left = xCenter - radius;
    128             mArcRect.right = xCenter + radius;
    129             redPercent = Math.min(1, (float) mTimer.getElapsedTime() / (float) mTimer.getTotalLength());
    130             final float whitePercent = 1 - redPercent;
    131 
    132             // Draw a white arc to indicate the amount of timer that remains.
    133             canvas.drawArc(mArcRect, 270, whitePercent * 360, false, mPaint);
    134 
    135             // Draw a red arc to indicate the amount of timer completed.
    136             mPaint.setColor(mCompletedColor);
    137             canvas.drawArc(mArcRect, 270, -redPercent * 360 , false, mPaint);
    138         }
    139 
    140         // Draw a red dot to indicate current progress through the timer.
    141         final float dotAngleDegrees = 270 - redPercent * 360;
    142         final double dotAngleRadians = Math.toRadians(dotAngleDegrees);
    143         final float dotX = xCenter + (float) (radius * Math.cos(dotAngleRadians));
    144         final float dotY = yCenter + (float) (radius * Math.sin(dotAngleRadians));
    145         canvas.drawCircle(dotX, dotY, mDotRadius, mFill);
    146 
    147         if (mTimer.isRunning()) {
    148             postInvalidateOnAnimation();
    149         }
    150     }
    151 }
    152