1f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/* 2f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Copyright (C) 2014 The Android Open Source Project 3f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 4f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Licensed under the Apache License, Version 2.0 (the "License"); 5f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * you may not use this file except in compliance with the License. 6f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * You may obtain a copy of the License at 7f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 8f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * http://www.apache.org/licenses/LICENSE-2.0 9f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * 10f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Unless required by applicable law or agreed to in writing, software 11f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * distributed under the License is distributed on an "AS IS" BASIS, 12f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * See the License for the specific language governing permissions and 14f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * limitations under the License. 15f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */ 16f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 17f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpackage com.google.android.apps.common.testing.ui.espresso.base; 18f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 19f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.android.apps.common.testing.ui.espresso.IdlingResourceTimeoutException; 20f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport com.google.common.base.Optional; 21f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 22f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.Build; 23f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.Handler; 24f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.Looper; 25f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.os.Message; 26f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.test.suitebuilder.annotation.LargeTest; 27f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport android.util.Log; 28f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 29f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport junit.framework.TestCase; 30f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 31f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.CountDownLatch; 32f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.LinkedBlockingQueue; 33f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.ThreadPoolExecutor; 34f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.TimeUnit; 35f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.atomic.AtomicReference; 36f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 37f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/** 38f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Unit test for {@link UiControllerImpl}. 39f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */ 40f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpublic class UiControllerImplTest extends TestCase { 41f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 42f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private static final String TAG = UiControllerImplTest.class.getSimpleName(); 43f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 44f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private LooperThread testThread; 45f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private AtomicReference<UiControllerImpl> uiController = new AtomicReference<UiControllerImpl>(); 46f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private ThreadPoolExecutor asyncPool; 47f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private IdlingResourceRegistry idlingResourceRegistry; 48f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 49f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private static class LooperThread extends Thread { 50f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private final CountDownLatch init = new CountDownLatch(1); 51f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private Handler handler; 52f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private Looper looper; 53f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 54f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 55f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 56f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Looper.prepare(); 57f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev handler = new Handler(); 58f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev looper = Looper.myLooper(); 59f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev init.countDown(); 60f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Looper.loop(); 61f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 62f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 63f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void quitLooper() { 64f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev looper.quit(); 65f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 66f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 67f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public Looper getLooper() { 68f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 69f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev init.await(); 70f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException ie) { 71f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Thread.currentThread().interrupt(); 72f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 73f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev return looper; 74f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 75f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 76f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public Handler getHandler() { 77f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 78f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev init.await(); 79f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException ie) { 80f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Thread.currentThread().interrupt(); 81f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 82f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev return handler; 83f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 84f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 85f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 86f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 87f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void setUp() throws Exception { 88f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev super.setUp(); 89f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread = new LooperThread(); 90f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 91f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 92f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void uncaughtException(Thread thread, Throwable ex) { 93f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.e(TAG, "Looper died: ", ex); 94f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 95f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 96f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.start(); 97f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry = new IdlingResourceRegistry(testThread.getLooper()); 98f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncPool = new ThreadPoolExecutor(3, 3, 1, TimeUnit.SECONDS, 99f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new LinkedBlockingQueue<Runnable>()); 100f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev EventInjector injector = null; 101f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (Build.VERSION.SDK_INT > 15) { 102f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev InputManagerEventInjectionStrategy strat = new InputManagerEventInjectionStrategy(); 103f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev strat.initialize(); 104f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector = new EventInjector(strat); 105f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } else { 106f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev WindowManagerEventInjectionStrategy strat = new WindowManagerEventInjectionStrategy(); 107f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev strat.initialize(); 108f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector = new EventInjector(strat); 109f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 110f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.set(new UiControllerImpl( 111f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev injector, 112f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new AsyncTaskPoolMonitor(asyncPool), 113f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Optional.<AsyncTaskPoolMonitor>absent(), 114f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry, 115f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.getLooper() 116f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev )); 117f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 118f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 119f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 120f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 121f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 122f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void tearDown() throws Exception { 123f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.quitLooper(); 124f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncPool.shutdown(); 125f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev super.tearDown(); 126f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 127f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 128f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadTillIdle_sendsMessageToRightHandler() { 129f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(3); 130f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.getHandler(); // blocks till initialized; 131f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final Handler firstHandler = new Handler( 132f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.looper, 133f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new Handler.Callback() { 134f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private boolean counted = false; 135f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 136f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public boolean handleMessage(Message me) { 137f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (counted) { 138f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Called 2x!!!!"); 139f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 140f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev counted = true; 141f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 142f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev return true; 143f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 144f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 145f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 146f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final Handler secondHandler = new Handler( 147f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.looper, 148f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new Handler.Callback() { 149f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev private boolean counted = false; 150f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 151f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public boolean handleMessage(Message me) { 152f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev if (counted) { 153f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Called 2x!!!!"); 154f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 155f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev counted = true; 156f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 157f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev return true; 158f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 159f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 160f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 161f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 162f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 163f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 164f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev firstHandler.sendEmptyMessage(1); 165f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev secondHandler.sendEmptyMessage(1); 166f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 167f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 168f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 169f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 170f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 171f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 172f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 173f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue( 174f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Timed out waiting for looper to process all events", latch.await(10, TimeUnit.SECONDS)); 175f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException e) { 176f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Failed with exception " + e); 177f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 178f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 179f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 180f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopForAtLeast() throws Exception { 181f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(2); 182f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 183f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 184f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 185f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev testThread.getHandler().post(new Runnable() { 186f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 187f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 188f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 189f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 190f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 191f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 192f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadForAtLeast(1000); 193f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 194f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 195f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 196f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("Never returned from UiControllerImpl.loopMainThreadForAtLeast();", 197f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.await(10, TimeUnit.SECONDS)); 198f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 199f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 200f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_fullQueue() { 201f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(3); 202f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 203f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 204f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 205f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "On main thread"); 206f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Handler handler = new Handler(); 207f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Equeueing test runnable 1"); 208f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev handler.post(new Runnable() { 209f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 210f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 211f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Running test runnable 1"); 212f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 213f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 214f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 215f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Equeueing test runnable 2"); 216f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev handler.post(new Runnable() { 217f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 218f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 219f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Running test runnable 2"); 220f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 221f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 222f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 223f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Hijacking thread and looping it."); 224f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 225f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 226f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 227f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 228f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 229f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 230f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue( 231f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Timed out waiting for looper to process all events", latch.await(10, TimeUnit.SECONDS)); 232f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException e) { 233f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Failed with exception " + e); 234f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 235f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 236f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 237f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_fullQueueAndAsyncTasks() throws Exception { 238f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(3); 239f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch asyncTaskStarted = new CountDownLatch(1); 240f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch asyncTaskShouldComplete = new CountDownLatch(1); 241f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncPool.execute(new Runnable() { 242f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 243f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 244f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncTaskStarted.countDown(); 245f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev while (true) { 246f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 247f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncTaskShouldComplete.await(); 248f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev return; 249f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException ie) { 250f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev // cant interrupt me. ignore. 251f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 252f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 253f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 254f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 255f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("async task is not starting!", asyncTaskStarted.await(2, TimeUnit.SECONDS)); 256f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 257f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 258f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 259f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 260f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "On main thread"); 261f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Handler handler = new Handler(); 262f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Equeueing test runnable 1"); 263f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev handler.post(new Runnable() { 264f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 265f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 266f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Running test runnable 1"); 267f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 268f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 269f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 270f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Equeueing test runnable 2"); 271f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev handler.post(new Runnable() { 272f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 273f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 274f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Running test runnable 2"); 275f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 276f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 277f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev }); 278f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Hijacking thread and looping it."); 279f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 280f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 281f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 282f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 283f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 284f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(2, TimeUnit.SECONDS)); 285f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertEquals("Not all main thread tasks have checked in", 1L, latch.getCount()); 286f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev asyncTaskShouldComplete.countDown(); 287f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); 288f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 289f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 290f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 291f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_emptyQueue() { 292f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(1); 293f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 294f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 295f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 296f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 297f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 298f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 299f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 300f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 301f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("Never returned from UiControllerImpl.loopMainThreadUntilIdle();", 302f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.await(10, TimeUnit.SECONDS)); 303f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (InterruptedException e) { 304f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fail("Failed with exception " + e); 305f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 306f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 307f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 308f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_oneIdlingResource() throws InterruptedException { 309f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource fakeResource = new OnDemandIdlingResource("FakeResource"); 310f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(fakeResource); 311f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(1); 312f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 313f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 314f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 315f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Hijacking thread and looping it."); 316f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 317f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 318f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 319f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 320f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 321f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(2, TimeUnit.SECONDS)); 322f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fakeResource.forceIdleNow(); 323f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); 324f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 325f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 326f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_multipleIdlingResources() throws InterruptedException { 327f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource fakeResource1 = new OnDemandIdlingResource("FakeResource1"); 328f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource fakeResource2 = new OnDemandIdlingResource("FakeResource2"); 329f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource fakeResource3 = new OnDemandIdlingResource("FakeResource3"); 330f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev // Register the first two right away and one later (once the wait for the first two begins). 331f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(fakeResource1); 332f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(fakeResource2); 333f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(1); 334f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 335f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 336f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 337f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Hijacking thread and looping it."); 338f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 339f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 340f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 341f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 342f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 343f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); 344f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fakeResource1.forceIdleNow(); 345f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 346f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); 347f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(fakeResource3); 348f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 349f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); 350f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fakeResource2.forceIdleNow(); 351f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 352f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(1, TimeUnit.SECONDS)); 353f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev fakeResource3.forceIdleNow(); 354f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue("App should be idle.", latch.await(5, TimeUnit.SECONDS)); 355f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 356f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 357f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @LargeTest 358f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void testLoopMainThreadUntilIdle_timeout() throws InterruptedException { 359f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource goodResource = 360f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new OnDemandIdlingResource("GoodResource"); 361f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource kindaCrappyResource = 362f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new OnDemandIdlingResource("KindaCrappyResource"); 363f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev OnDemandIdlingResource badResource = 364f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev new OnDemandIdlingResource("VeryBadResource"); 365f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(goodResource); 366f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(kindaCrappyResource); 367f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev idlingResourceRegistry.register(badResource); 368f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev final CountDownLatch latch = new CountDownLatch(1); 369f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue(testThread.getHandler().post(new Runnable() { 370f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev @Override 371f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev public void run() { 372f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev Log.i(TAG, "Hijacking thread and looping it."); 373f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev try { 374f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev uiController.get().loopMainThreadUntilIdle(); 375f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } catch (IdlingResourceTimeoutException e) { 376f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev latch.countDown(); 377f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 378f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 379f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev })); 380f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 381f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(4, TimeUnit.SECONDS)); 382f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev goodResource.forceIdleNow(); 383f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertFalse( 384f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should not have stopped looping the main thread yet!", latch.await(12, TimeUnit.SECONDS)); 385f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev kindaCrappyResource.forceIdleNow(); 386f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev assertTrue( 387f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev "Should have caught IdlingResourceTimeoutException", latch.await(11, TimeUnit.SECONDS)); 388f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev } 389f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev 390f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev} 391