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