1 /*
2  * Copyright (C) 2020 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.wm.shell.common;
18 
19 import java.lang.reflect.Array;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.Executor;
22 import java.util.concurrent.TimeUnit;
23 import java.util.function.Supplier;
24 
25 /**
26  * Super basic Executor interface that adds support for delayed execution and removing callbacks.
27  * Intended to wrap Handler while better-supporting testing.
28  */
29 public interface ShellExecutor extends Executor {
30 
31     /**
32      * Executes the given runnable. If the caller is running on the same looper as this executor,
33      * the runnable must be executed immediately.
34      */
35     @Override
execute(Runnable runnable)36     void execute(Runnable runnable);
37 
38     /**
39      * Executes the given runnable in a blocking call. If the caller is running on the same looper
40      * as this executor, the runnable must be executed immediately.
41      *
42      * @throws InterruptedException if runnable does not return in the time specified by
43      *                              {@param waitTimeout}
44      */
executeBlocking(Runnable runnable, int waitTimeout, TimeUnit waitTimeUnit)45     default void executeBlocking(Runnable runnable, int waitTimeout, TimeUnit waitTimeUnit)
46             throws InterruptedException {
47         final CountDownLatch latch = new CountDownLatch(1);
48         execute(() -> {
49             runnable.run();
50             latch.countDown();
51         });
52         latch.await(waitTimeout, waitTimeUnit);
53     }
54 
55     /**
56      * Convenience method to execute the blocking call with a default timeout.
57      *
58      * @throws InterruptedException if runnable does not return in the time specified by
59      *                              {@param waitTimeout}
60      */
executeBlocking(Runnable runnable)61     default void executeBlocking(Runnable runnable) throws InterruptedException {
62         executeBlocking(runnable, 2, TimeUnit.SECONDS);
63     }
64 
65     /**
66      * Convenience method to execute the blocking call with a default timeout and returns a value.
67      * Waits indefinitely for a typed result from a call.
68      */
executeBlockingForResult(Supplier<T> runnable, Class clazz)69     default <T> T executeBlockingForResult(Supplier<T> runnable, Class clazz) {
70         final T[] result = (T[]) Array.newInstance(clazz, 1);
71         final CountDownLatch latch = new CountDownLatch(1);
72         execute(() -> {
73             result[0] = runnable.get();
74             latch.countDown();
75         });
76         try {
77             latch.await();
78             return result[0];
79         } catch (InterruptedException e) {
80             return null;
81         }
82     }
83 
84 
85     /**
86      * See {@link android.os.Handler#postDelayed(Runnable, long)}.
87      */
executeDelayed(Runnable runnable, long delayMillis)88     void executeDelayed(Runnable runnable, long delayMillis);
89 
90     /**
91      * See {@link android.os.Handler#removeCallbacks}.
92      */
removeCallbacks(Runnable runnable)93     void removeCallbacks(Runnable runnable);
94 
95     /**
96      * See {@link android.os.Handler#hasCallbacks(Runnable)}.
97      */
hasCallback(Runnable runnable)98     boolean hasCallback(Runnable runnable);
99 }
100