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