1/* 2 * Copyright (C) 2017 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 17package androidx.wear.widget; 18 19import android.os.CountDownTimer; 20 21import androidx.annotation.Nullable; 22import androidx.annotation.VisibleForTesting; 23 24/** 25 * Controller for {@link CircularProgressLayout}. 26 */ 27class CircularProgressLayoutController { 28 29 private final CircularProgressLayout mLayout; 30 @VisibleForTesting CountDownTimer mTimer; 31 private boolean mIsIndeterminate; 32 private boolean mIsTimerRunning; 33 34 /** 35 * Called when the timer is finished. 36 */ 37 @Nullable 38 private CircularProgressLayout.OnTimerFinishedListener mOnTimerFinishedListener; 39 40 CircularProgressLayoutController(CircularProgressLayout layout) { 41 mLayout = layout; 42 } 43 44 /** 45 * Returns the registered {@link CircularProgressLayout.OnTimerFinishedListener}. 46 */ 47 @Nullable 48 public CircularProgressLayout.OnTimerFinishedListener getOnTimerFinishedListener() { 49 return mOnTimerFinishedListener; 50 } 51 52 /** 53 * Sets the {@link CircularProgressLayout.OnTimerFinishedListener} to be notified when timer 54 * countdown is finished. 55 */ 56 public void setOnTimerFinishedListener( 57 @Nullable CircularProgressLayout.OnTimerFinishedListener listener) { 58 mOnTimerFinishedListener = listener; 59 } 60 61 /** Returns true if the progress is shown as an indeterminate spinner. */ 62 boolean isIndeterminate() { 63 return mIsIndeterminate; 64 } 65 66 /** Returns true if timer is running. */ 67 boolean isTimerRunning() { 68 return mIsTimerRunning; 69 } 70 71 /** Sets if the progress should be shown as an indeterminate spinner. */ 72 void setIndeterminate(boolean indeterminate) { 73 if (mIsIndeterminate == indeterminate) { 74 return; 75 } 76 mIsIndeterminate = indeterminate; 77 if (mIsIndeterminate) { 78 if (mIsTimerRunning) { 79 stopTimer(); 80 } 81 mLayout.getProgressDrawable().start(); 82 } else { 83 mLayout.getProgressDrawable().stop(); 84 } 85 } 86 87 void startTimer(long totalTime, long updateInterval) { 88 reset(); 89 mIsTimerRunning = true; 90 mTimer = new CircularProgressTimer(totalTime, updateInterval); 91 mTimer.start(); 92 } 93 94 void stopTimer() { 95 if (mIsTimerRunning) { 96 mTimer.cancel(); 97 mIsTimerRunning = false; 98 mLayout.getProgressDrawable().setStartEndTrim(0f, 0f); // Reset the progress 99 } 100 } 101 102 /** 103 * Resets everything. 104 */ 105 void reset() { 106 setIndeterminate(false); // If showing indeterminate progress, stop it 107 stopTimer(); // Stop the previous timer if there is one 108 mLayout.getProgressDrawable().setStartEndTrim(0f, 0f); // Reset the progress 109 } 110 111 /** 112 * Class to handle timing for {@link CircularProgressLayout}. 113 */ 114 private class CircularProgressTimer extends CountDownTimer { 115 116 private final long mTotalTime; 117 118 CircularProgressTimer(long totalTime, long updateInterval) { 119 super(totalTime, updateInterval); 120 mTotalTime = totalTime; 121 } 122 123 @Override 124 public void onTick(long millisUntilFinished) { 125 mLayout.getProgressDrawable() 126 .setStartEndTrim(0f, 1f - (float) millisUntilFinished / (float) mTotalTime); 127 mLayout.invalidate(); 128 } 129 130 @Override 131 public void onFinish() { 132 mLayout.getProgressDrawable().setStartEndTrim(0f, 1f); 133 if (mOnTimerFinishedListener != null) { 134 mOnTimerFinishedListener.onTimerFinished(mLayout); 135 } 136 mIsTimerRunning = false; 137 } 138 } 139} 140