blob: 7475cd7e1e36040489509787ecd9596cb049bc15 [file] [log] [blame]
Chris Wren930ecca2014-11-12 17:43:41 -05001/*
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 */
16package com.android.systemui;
17
Jason Monk893f0bd2017-06-01 11:21:14 -040018import static org.mockito.Mockito.spy;
19import static org.mockito.Mockito.when;
20
21import android.app.Instrumentation;
Jason Monk86bc3312016-08-16 13:17:56 -040022import android.os.Handler;
23import android.os.Looper;
24import android.os.MessageQueue;
Winson Chung16e185e2017-11-07 08:30:54 -080025import android.os.ParcelFileDescriptor;
Jason Monkaa573e92017-01-27 17:00:29 -050026import android.support.test.InstrumentationRegistry;
Adrian Roos3150dbf2018-03-28 18:06:52 +020027import android.testing.DexmakerShareClassLoaderRule;
Jason Monk340b0e52017-03-08 14:57:56 -050028import android.testing.LeakCheck;
Jorim Jaggie549a8d2017-05-15 02:40:05 +020029import android.util.Log;
Jason Monke9789282016-11-09 08:59:56 -050030
Jason Monk893f0bd2017-06-01 11:21:14 -040031import org.junit.After;
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040032import org.junit.Before;
Jason Monk340b0e52017-03-08 14:57:56 -050033import org.junit.Rule;
Chris Wren930ecca2014-11-12 17:43:41 -050034
Winson Chung16e185e2017-11-07 08:30:54 -080035import java.io.FileInputStream;
36import java.io.IOException;
Jorim Jaggie549a8d2017-05-15 02:40:05 +020037import java.util.concurrent.ExecutionException;
38import java.util.concurrent.Future;
39
Chris Wren930ecca2014-11-12 17:43:41 -050040/**
41 * Base class that does System UI specific setup.
42 */
Jason Monk9abca5e2016-11-11 16:18:14 -050043public abstract class SysuiTestCase {
Jason Monk86bc3312016-08-16 13:17:56 -040044
Jorim Jaggie549a8d2017-05-15 02:40:05 +020045 private static final String TAG = "SysuiTestCase";
46
Jason Monk86bc3312016-08-16 13:17:56 -040047 private Handler mHandler;
Jason Monk340b0e52017-03-08 14:57:56 -050048 @Rule
49 public SysuiTestableContext mContext = new SysuiTestableContext(
50 InstrumentationRegistry.getContext(), getLeakCheck());
Adrian Roos3150dbf2018-03-28 18:06:52 +020051 @Rule
52 public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
53 new DexmakerShareClassLoaderRule();
Jason Monk340b0e52017-03-08 14:57:56 -050054 public TestableDependency mDependency = new TestableDependency(mContext);
Jason Monk893f0bd2017-06-01 11:21:14 -040055 private Instrumentation mRealInstrumentation;
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040056
57 @Before
58 public void SysuiSetup() throws Exception {
Lucas Dupin6865b712017-09-11 12:28:03 -070059 mContext.setTheme(R.style.Theme_SystemUI);
Jason Monk685db722017-01-23 17:36:50 -050060 SystemUIFactory.createFromConfig(mContext);
Jason Monk893f0bd2017-06-01 11:21:14 -040061
62 mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
63 Instrumentation inst = spy(mRealInstrumentation);
Jason Monkc429f692017-06-27 13:13:49 -040064 when(inst.getContext()).thenAnswer(invocation -> {
65 throw new RuntimeException(
66 "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
67 });
68 when(inst.getTargetContext()).thenAnswer(invocation -> {
69 throw new RuntimeException(
70 "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
71 });
Jason Monk893f0bd2017-06-01 11:21:14 -040072 InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
73 }
74
75 @After
76 public void SysuiTeardown() {
77 InstrumentationRegistry.registerInstance(mRealInstrumentation,
78 InstrumentationRegistry.getArguments());
Jason Monke9789282016-11-09 08:59:56 -050079 }
80
Jason Monk340b0e52017-03-08 14:57:56 -050081 protected LeakCheck getLeakCheck() {
82 return null;
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040083 }
84
Julia Reynolds5daa4722017-12-20 09:53:59 -050085 public SysuiTestableContext getContext() {
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040086 return mContext;
Chris Wren930ecca2014-11-12 17:43:41 -050087 }
Jason Monk86bc3312016-08-16 13:17:56 -040088
Winson Chung16e185e2017-11-07 08:30:54 -080089 protected void runShellCommand(String command) throws IOException {
90 ParcelFileDescriptor pfd = mRealInstrumentation.getUiAutomation()
91 .executeShellCommand(command);
92
93 // Read the input stream fully.
94 FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
95 while (fis.read() != -1);
96 fis.close();
97 }
98
Jason Monk86bc3312016-08-16 13:17:56 -040099 protected void waitForIdleSync() {
100 if (mHandler == null) {
101 mHandler = new Handler(Looper.getMainLooper());
102 }
103 waitForIdleSync(mHandler);
104 }
105
Jorim Jaggie549a8d2017-05-15 02:40:05 +0200106 protected void waitForUiOffloadThread() {
107 Future<?> future = Dependency.get(UiOffloadThread.class).submit(() -> {});
108 try {
109 future.get();
110 } catch (InterruptedException | ExecutionException e) {
111 Log.e(TAG, "Failed to wait for ui offload thread.", e);
112 }
113 }
114
Jason Monkde850bb2017-02-01 19:26:30 -0500115 public static void waitForIdleSync(Handler h) {
Jason Monk86bc3312016-08-16 13:17:56 -0400116 validateThread(h.getLooper());
117 Idler idler = new Idler(null);
118 h.getLooper().getQueue().addIdleHandler(idler);
119 // Ensure we are non-idle, so the idle handler can run.
120 h.post(new EmptyRunnable());
121 idler.waitForIdle();
122 }
123
124 private static final void validateThread(Looper l) {
125 if (Looper.myLooper() == l) {
126 throw new RuntimeException(
127 "This method can not be called from the looper being synced");
128 }
129 }
130
131 public static final class EmptyRunnable implements Runnable {
132 public void run() {
133 }
134 }
135
136 public static final class Idler implements MessageQueue.IdleHandler {
137 private final Runnable mCallback;
138 private boolean mIdle;
139
140 public Idler(Runnable callback) {
141 mCallback = callback;
142 mIdle = false;
143 }
144
145 @Override
146 public boolean queueIdle() {
147 if (mCallback != null) {
148 mCallback.run();
149 }
150 synchronized (this) {
151 mIdle = true;
152 notifyAll();
153 }
154 return false;
155 }
156
157 public void waitForIdle() {
158 synchronized (this) {
159 while (!mIdle) {
160 try {
161 wait();
162 } catch (InterruptedException e) {
163 }
164 }
165 }
166 }
167 }
Chris Wren930ecca2014-11-12 17:43:41 -0500168}