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.systemui.util;
18 
19 import android.os.Looper;
20 
21 import androidx.annotation.VisibleForTesting;
22 
23 /**
24  * Helper providing common assertions.
25  */
26 public class Assert {
27     private static final Looper sMainLooper = Looper.getMainLooper();
28     private static Thread sTestThread = null;
29 
30     @VisibleForTesting
setTestableLooper(Looper testLooper)31     public static void setTestableLooper(Looper testLooper) {
32         setTestThread(testLooper == null ? null : testLooper.getThread());
33     }
34 
35     @VisibleForTesting
setTestThread(Thread thread)36     public static void setTestThread(Thread thread) {
37         sTestThread = thread;
38     }
39 
40     /**
41      * Run {@code mainThreadWork} synchronously, ensuring that {@link #isMainThread()} will return
42      * {@code true} while it is running.
43      * <ol>
44      * <li>If {@link #isMainThread()} already passes, the work is simply run.
45      * <li>If the test thread is {@code null}, it will be set, the work run, and then cleared.
46      * <li>If the test thread is already set to a different thread, this call will fail the test to
47      * avoid causing spurious errors on other thread
48      * </ol>
49      */
50     @VisibleForTesting
runWithCurrentThreadAsMainThread(Runnable mainThreadWork)51     public static void runWithCurrentThreadAsMainThread(Runnable mainThreadWork) {
52         if (sMainLooper.isCurrentThread()) {
53             // Already on the main thread; just run
54             mainThreadWork.run();
55             return;
56         }
57         Thread currentThread = Thread.currentThread();
58         Thread originalThread = sTestThread;
59         if (originalThread == currentThread) {
60             // test thread is already set; just run
61             mainThreadWork.run();
62             return;
63         }
64         if (originalThread != null) {
65             throw new AssertionError("Can't run with current thread (" + currentThread
66                     + ") as main thread; test thread is already set to " + originalThread);
67         }
68         sTestThread = currentThread;
69         mainThreadWork.run();
70         sTestThread = null;
71     }
72 
isMainThread()73     public static void isMainThread() {
74         if (!sMainLooper.isCurrentThread()
75                 && (sTestThread == null || sTestThread != Thread.currentThread())) {
76             throw new IllegalStateException("should be called from the main thread."
77                     + " sMainLooper.threadName=" + sMainLooper.getThread().getName()
78                     + " Thread.currentThread()=" + Thread.currentThread().getName());
79         }
80     }
81 
82     /**
83      * Asserts that the current thread is the same as the given thread, or that the current thread
84      * is the test thread.
85      * @param expected The looper we expected to be running on
86      */
isCurrentThread(Looper expected)87     public static void isCurrentThread(Looper expected) {
88         if (!expected.isCurrentThread()
89                 && (sTestThread == null || sTestThread != Thread.currentThread())) {
90             throw new IllegalStateException("Called on wrong thread thread."
91                     + " wanted " + expected.getThread().getName()
92                     + " but instead got Thread.currentThread()="
93                     + Thread.currentThread().getName());
94         }
95     }
96 
isNotMainThread()97     public static void isNotMainThread() {
98         if (sMainLooper.isCurrentThread()
99                 && (sTestThread == null || sTestThread == Thread.currentThread())) {
100             throw new IllegalStateException("should not be called from the main thread.");
101         }
102     }
103 }
104