1 /*
2  * Copyright (C) 2012 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.compatibility.common.util;
18 
19 import junit.framework.Assert;
20 
21 import java.util.concurrent.Callable;
22 import java.util.function.BooleanSupplier;
23 import java.util.function.Function;
24 import java.util.function.Supplier;
25 
26 public abstract class PollingCheck {
27     private static final long TIME_SLICE = 50;
28     private static final long DEFAULT_TIMEOUT = 3_000;
29     private static final String DEFAULT_ERROR_MESSAGE = "unexpected timeout";
30 
31     private final long mTimeout;
32     private final String mErrorMessage;
33 
34     public static interface PollingCheckCondition {
canProceed()35         boolean canProceed();
36     }
37 
PollingCheck()38     public PollingCheck() {
39         this(DEFAULT_TIMEOUT, DEFAULT_ERROR_MESSAGE);
40     }
41 
PollingCheck(long timeout)42     public PollingCheck(long timeout) {
43         this(timeout, DEFAULT_ERROR_MESSAGE);
44     }
45 
PollingCheck(long timeout, String errorMessage)46     public PollingCheck(long timeout, String errorMessage) {
47         mTimeout = timeout;
48         mErrorMessage = errorMessage;
49     }
50 
PollingCheck(String errorMessage)51     public PollingCheck(String errorMessage) {
52         this(DEFAULT_TIMEOUT, errorMessage);
53     }
54 
check()55     protected abstract boolean check();
56 
getErrorMessage()57     protected String getErrorMessage() {
58         return mErrorMessage;
59     }
60 
run()61     public void run() {
62         if (check()) {
63             return;
64         }
65 
66         long timeout = mTimeout;
67         while (timeout > 0) {
68             try {
69                 Thread.sleep(TIME_SLICE);
70             } catch (InterruptedException e) {
71                 Assert.fail("unexpected InterruptedException");
72             }
73 
74             if (check()) {
75                 return;
76             }
77 
78             timeout -= TIME_SLICE;
79         }
80 
81         Assert.assertTrue(getErrorMessage(), check());
82     }
83 
runWaitAndReturnResult(Supplier<E> supplier, Function<E, Boolean> condition)84     public <E> E runWaitAndReturnResult(Supplier<E> supplier, Function<E, Boolean> condition) {
85         E output = supplier.get();
86         if (condition.apply(output)) {
87             return output;
88         }
89         long timeout = mTimeout;
90         while (timeout > 0) {
91             try {
92                 Thread.sleep(TIME_SLICE);
93             } catch (InterruptedException e) {
94                 Assert.fail("unexpected InterruptedException");
95             }
96 
97             output = supplier.get();
98             if (condition.apply(output)) {
99                 return output;
100             }
101 
102             timeout -= TIME_SLICE;
103         }
104 
105         return output;
106     }
107 
check(CharSequence message, long timeout, Callable<Boolean> condition)108     public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
109             throws Exception {
110         while (timeout > 0) {
111             if (condition.call()) {
112                 return;
113             }
114 
115             Thread.sleep(TIME_SLICE);
116             timeout -= TIME_SLICE;
117         }
118 
119         Assert.fail(message.toString());
120     }
121 
waitFor(final PollingCheckCondition condition)122     public static void waitFor(final PollingCheckCondition condition) {
123         new PollingCheck() {
124             @Override
125             protected boolean check() {
126                 return condition.canProceed();
127             }
128         }.run();
129     }
130 
waitFor(final PollingCheckCondition condition, String errorMessage)131     public static void waitFor(final PollingCheckCondition condition, String errorMessage) {
132         new PollingCheck(errorMessage) {
133             @Override
134             protected boolean check() {
135                 return condition.canProceed();
136             }
137         }.run();
138     }
139 
waitFor(long timeout, final PollingCheckCondition condition)140     public static void waitFor(long timeout, final PollingCheckCondition condition) {
141         new PollingCheck(timeout) {
142             @Override
143             protected boolean check() {
144                 return condition.canProceed();
145             }
146         }.run();
147     }
148 
waitFor(long timeout, final PollingCheckCondition condition, Supplier<String> errorMessage)149     public static void waitFor(long timeout, final PollingCheckCondition condition,
150             Supplier<String> errorMessage) {
151         new PollingCheck(timeout) {
152             @Override
153             protected boolean check() {
154                 return condition.canProceed();
155             }
156 
157             @Override
158             protected String getErrorMessage() {
159                 return errorMessage.get();
160             }
161         }.run();
162     }
163 
waitFor(long timeout, BooleanSupplier condition, String errorMessage)164     public static void waitFor(long timeout, BooleanSupplier condition, String errorMessage) {
165         new PollingCheck(timeout, errorMessage) {
166             @Override
167             protected boolean check() {
168                 return condition.getAsBoolean();
169             }
170         }.run();
171     }
172 
waitFor(long timeout, Supplier<E> supplier, Function<E, Boolean> condition)173     public static <E> E waitFor(long timeout, Supplier<E> supplier,
174             Function<E, Boolean> condition) {
175         return new PollingCheck(timeout) {
176             // Not used in the corresponding runWaitAndReturnResult function, Added just to provide
177             // default implementation of abstract check function.
178             @Override
179             protected boolean check() {
180                 return true;
181             }
182         }.runWaitAndReturnResult(supplier, condition);
183     }
184 }
185