• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 package com.android.systemui;
17 
18 import static org.mockito.Mockito.spy;
19 import static org.mockito.Mockito.when;
20 
21 import android.app.Instrumentation;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.MessageQueue;
25 import android.os.ParcelFileDescriptor;
26 import android.support.test.InstrumentationRegistry;
27 import android.testing.DexmakerShareClassLoaderRule;
28 import android.testing.LeakCheck;
29 import android.util.Log;
30 
31 import com.android.keyguard.KeyguardUpdateMonitor;
32 
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Rule;
36 
37 import java.io.FileInputStream;
38 import java.io.IOException;
39 import java.util.concurrent.ExecutionException;
40 import java.util.concurrent.Future;
41 
42 /**
43  * Base class that does System UI specific setup.
44  */
45 public abstract class SysuiTestCase {
46 
47     private static final String TAG = "SysuiTestCase";
48 
49     private Handler mHandler;
50     @Rule
51     public SysuiTestableContext mContext = new SysuiTestableContext(
52             InstrumentationRegistry.getContext(), getLeakCheck());
53     @Rule
54     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
55             new DexmakerShareClassLoaderRule();
56     public TestableDependency mDependency = new TestableDependency(mContext);
57     private Instrumentation mRealInstrumentation;
58 
59     @Before
SysuiSetup()60     public void SysuiSetup() throws Exception {
61         mContext.setTheme(R.style.Theme_SystemUI);
62         SystemUIFactory.createFromConfig(mContext);
63 
64         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
65         Instrumentation inst = spy(mRealInstrumentation);
66         when(inst.getContext()).thenAnswer(invocation -> {
67             throw new RuntimeException(
68                     "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
69         });
70         when(inst.getTargetContext()).thenAnswer(invocation -> {
71             throw new RuntimeException(
72                     "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
73         });
74         InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
75         KeyguardUpdateMonitor.disableHandlerCheckForTesting(inst);
76     }
77 
78     @After
SysuiTeardown()79     public void SysuiTeardown() {
80         InstrumentationRegistry.registerInstance(mRealInstrumentation,
81                 InstrumentationRegistry.getArguments());
82     }
83 
getLeakCheck()84     protected LeakCheck getLeakCheck() {
85         return null;
86     }
87 
getContext()88     public SysuiTestableContext getContext() {
89         return mContext;
90     }
91 
runShellCommand(String command)92     protected void runShellCommand(String command) throws IOException {
93         ParcelFileDescriptor pfd = mRealInstrumentation.getUiAutomation()
94                 .executeShellCommand(command);
95 
96         // Read the input stream fully.
97         FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
98         while (fis.read() != -1);
99         fis.close();
100     }
101 
waitForIdleSync()102     protected void waitForIdleSync() {
103         if (mHandler == null) {
104             mHandler = new Handler(Looper.getMainLooper());
105         }
106         waitForIdleSync(mHandler);
107     }
108 
waitForUiOffloadThread()109     protected void waitForUiOffloadThread() {
110         Future<?> future = Dependency.get(UiOffloadThread.class).submit(() -> {});
111         try {
112             future.get();
113         } catch (InterruptedException | ExecutionException e) {
114             Log.e(TAG, "Failed to wait for ui offload thread.", e);
115         }
116     }
117 
waitForIdleSync(Handler h)118     public static void waitForIdleSync(Handler h) {
119         validateThread(h.getLooper());
120         Idler idler = new Idler(null);
121         h.getLooper().getQueue().addIdleHandler(idler);
122         // Ensure we are non-idle, so the idle handler can run.
123         h.post(new EmptyRunnable());
124         idler.waitForIdle();
125     }
126 
validateThread(Looper l)127     private static final void validateThread(Looper l) {
128         if (Looper.myLooper() == l) {
129             throw new RuntimeException(
130                 "This method can not be called from the looper being synced");
131         }
132     }
133 
134     public static final class EmptyRunnable implements Runnable {
run()135         public void run() {
136         }
137     }
138 
139     public static final class Idler implements MessageQueue.IdleHandler {
140         private final Runnable mCallback;
141         private boolean mIdle;
142 
Idler(Runnable callback)143         public Idler(Runnable callback) {
144             mCallback = callback;
145             mIdle = false;
146         }
147 
148         @Override
queueIdle()149         public boolean queueIdle() {
150             if (mCallback != null) {
151                 mCallback.run();
152             }
153             synchronized (this) {
154                 mIdle = true;
155                 notifyAll();
156             }
157             return false;
158         }
159 
waitForIdle()160         public void waitForIdle() {
161             synchronized (this) {
162                 while (!mIdle) {
163                     try {
164                         wait();
165                     } catch (InterruptedException e) {
166                     }
167                 }
168             }
169         }
170     }
171 }
172