1 /*
2  * Copyright (C) 2016 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.documentsui.testing;
18 
19 import java.util.Date;
20 import java.util.Iterator;
21 import java.util.LinkedList;
22 import java.util.ListIterator;
23 import java.util.Timer;
24 import java.util.TimerTask;
25 
26 /**
27  * A {@link Timer} for testing that can dial its clock hands to any future time.
28  */
29 public class TestTimer extends Timer {
30 
31     private long mNow = 0;
32 
33     private final LinkedList<Task> mTaskList = new LinkedList<>();
34 
getNow()35     public long getNow() {
36         return mNow;
37     }
38 
fastForwardTo(long time)39     public void fastForwardTo(long time) {
40         if (time < mNow) {
41             throw new IllegalArgumentException("Can't fast forward to past.");
42         }
43 
44         mNow = time;
45         while (!mTaskList.isEmpty() && mTaskList.getFirst().mExecuteTime <= mNow) {
46             Task task = mTaskList.getFirst();
47             if (!task.isCancelled()) {
48                 task.run();
49             }
50             mTaskList.removeFirst();
51         }
52     }
53 
hasScheduledTask()54     public boolean hasScheduledTask() {
55         return !mTaskList.isEmpty();
56     }
57 
fastForwardToNextTask()58     public void fastForwardToNextTask() {
59         if (!hasScheduledTask()) {
60             throw new IllegalStateException("There is no scheduled task!");
61         }
62         fastForwardTo(mTaskList.getFirst().mExecuteTime);
63     }
64 
65     @Override
cancel()66     public void cancel() {
67         mTaskList.clear();
68     }
69 
70     @Override
purge()71     public int purge() {
72         int count = 0;
73         Iterator<Task> iter = mTaskList.iterator();
74         while (iter.hasNext()) {
75             Task task = iter.next();
76             if (task.isCancelled()) {
77                 iter.remove();
78                 ++count;
79             }
80         }
81         return count;
82     }
83 
84     @Override
schedule(TimerTask task, Date time)85     public void schedule(TimerTask task, Date time) {
86         long executeTime = time.getTime();
87         scheduleAtTime(task, executeTime);
88     }
89 
90     @Override
schedule(TimerTask task, Date firstTime, long period)91     public void schedule(TimerTask task, Date firstTime, long period) {
92         throw new UnsupportedOperationException();
93     }
94 
95     @Override
schedule(TimerTask task, long delay)96     public void schedule(TimerTask task, long delay) {
97         long executeTime = mNow + delay;
98         scheduleAtTime(task, executeTime);
99     }
100 
101     @Override
schedule(TimerTask task, long delay, long period)102     public void schedule(TimerTask task, long delay, long period) {
103         throw new UnsupportedOperationException();
104     }
105 
106     @Override
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)107     public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
108         throw new UnsupportedOperationException();
109     }
110 
111     @Override
scheduleAtFixedRate(TimerTask task, long delay, long period)112     public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
113         throw new UnsupportedOperationException();
114     }
115 
scheduleAtTime(TimerTask task, long executeTime)116     public void scheduleAtTime(TimerTask task, long executeTime) {
117         Task testTimerTask = (Task) task;
118         testTimerTask.mExecuteTime = executeTime;
119 
120         ListIterator<Task> iter = mTaskList.listIterator(0);
121         while (iter.hasNext()) {
122             if (iter.next().mExecuteTime >= executeTime) {
123                 break;
124             }
125         }
126         iter.add(testTimerTask);
127     }
128 
129     public static class Task extends TimerTask {
130         private boolean mIsCancelled;
131         private long mExecuteTime;
132 
133         private TimerTask mDelegate;
134 
Task(TimerTask delegate)135         public Task(TimerTask delegate) {
136             mDelegate = delegate;
137         }
138 
139         @Override
cancel()140         public boolean cancel() {
141             mIsCancelled = true;
142             return mDelegate.cancel();
143         }
144 
145         @Override
run()146         public void run() {
147             mDelegate.run();
148         }
149 
isCancelled()150         boolean isCancelled() {
151             return mIsCancelled;
152         }
153     }
154 }
155