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.Utils;
     30 import com.android.deskclock.data.Timer;
     31 
     32 /**
     33  * Custom view that draws timer progress as a circle.
     34  */
     35 public final class TimerCircleView extends View {
     36 
     37     /** The size of the dot indicating the progress through the timer. */
     38     private final float mDotRadius;
     39 
     40     /** An amount to subtract from the true radius to account for drawing thicknesses. */
     41     private final float mRadiusOffset;
     42 
     43     /** The color indicating the remaining portion of the timer. */
     44     private final int mRemainderColor;
     45 
     46     /** The color indicating the completed portion of the timer. */
     47     private final int mCompletedColor;
     48 
     49     /** The size of the stroke that paints the timer circle. */
     50     private final float mStrokeSize;
     51 
     52     private final Paint mPaint = new Paint();
     53     private final Paint mFill = new Paint();
     54     private final RectF mArcRect = new RectF();
     55 
     56     private Timer mTimer;
     57 
     58     @SuppressWarnings("unused")
     59     public TimerCircleView(Context context) {
     60         this(context, null);
     61     }
     62 
     63     public TimerCircleView(Context context, AttributeSet attrs) {
     64         super(context, attrs);
     65 
     66         final Resources resources = context.getResources();
     67         final float dotDiameter = resources.getDimension(R.dimen.circletimer_dot_size);
     68 
     69         mDotRadius = dotDiameter / 2f;
     70         mStrokeSize = resources.getDimension(R.dimen.circletimer_circle_size);
     71         mRadiusOffset = Utils.calculateRadiusOffset(mStrokeSize, dotDiameter, 0);
     72 
     73         mRemainderColor = resources.getColor(R.color.clock_white);
     74         mCompletedColor = Utils.obtainStyledColor(context, R.attr.colorAccent, Color.RED);
     75 
     76         mPaint.setAntiAlias(true);
     77         mPaint.setStyle(Paint.Style.STROKE);
     78 
     79         mFill.setAntiAlias(true);
     80         mFill.setColor(mCompletedColor);
     81         mFill.setStyle(Paint.Style.FILL);
     82     }
     83 
     84     void update(Timer timer) {
     85         if (mTimer != timer) {
     86             mTimer = timer;
     87             postInvalidateOnAnimation();
     88         }
     89     }
     90 
     91     @Override
     92     public void onDraw(Canvas canvas) {
     93         if (mTimer == null) {
     94             return;
     95         }
     96 
     97         // Compute the size and location of the circle to be drawn.
     98         final int xCenter = getWidth() / 2;
     99         final int yCenter = getHeight() / 2;
    100         final float radius = Math.min(xCenter, yCenter) - mRadiusOffset;
    101 
    102         // Reset old painting state.
    103         mPaint.setColor(mRemainderColor);
    104         mPaint.setStrokeWidth(mStrokeSize);
    105 
    106         // If the timer is reset, draw a simple white circle.
    107         final float redPercent;
    108         if (mTimer.isReset()) {
    109             // Draw a complete white circle; no red arc required.
    110             canvas.drawCircle(xCenter, yCenter, radius, mPaint);
    111 
    112             // Red percent is 0 since no timer progress has been made.
    113             redPercent = 0;
    114         } else if (mTimer.isExpired()) {
    115             mPaint.setColor(mCompletedColor);
    116 
    117             // Draw a complete white circle; no red arc required.
    118             canvas.drawCircle(xCenter, yCenter, radius, mPaint);
    119 
    120             // Red percent is 1 since the timer has expired.
    121             redPercent = 1;
    122         } else {
    123             // Draw a combination of red and white arcs to create a circle.
    124             mArcRect.top = yCenter - radius;
    125             mArcRect.bottom = yCenter + radius;
    126             mArcRect.left = xCenter - radius;
    127             mArcRect.right = xCenter + radius;
    128             redPercent = Math.min(1, (float) mTimer.getElapsedTime() / (float) mTimer.getTotalLength());
    129             final float whitePercent = 1 - redPercent;
    130 
    131             // Draw a white arc to indicate the amount of timer that remains.
    132             canvas.drawArc(mArcRect, 270, whitePercent * 360, false, mPaint);
    133 
    134             // Draw a red arc to indicate the amount of timer completed.
    135             mPaint.setColor(mCompletedColor);
    136             canvas.drawArc(mArcRect, 270, -redPercent * 360 , false, mPaint);
    137         }
    138 
    139         // Draw a red dot to indicate current progress through the timer.
    140         final float dotAngleDegrees = 270 - redPercent * 360;
    141         final double dotAngleRadians = Math.toRadians(dotAngleDegrees);
    142         final float dotX = xCenter + (float) (radius * Math.cos(dotAngleRadians));
    143         final float dotY = yCenter + (float) (radius * Math.sin(dotAngleRadians));
    144         canvas.drawCircle(dotX, dotY, mDotRadius, mFill);
    145 
    146         if (mTimer.isRunning()) {
    147             postInvalidateOnAnimation();
    148         }
    149     }
    150 }
    151