1 /* 2 * Copyright (C) 2015 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 android.car.apitest; 17 18 import static android.car.CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED; 19 import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION; 20 import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND; 21 22 import android.car.Car; 23 import android.car.CarAppFocusManager; 24 import android.car.CarNotConnectedException; 25 import android.content.Context; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.test.suitebuilder.annotation.MediumTest; 29 import android.util.Log; 30 31 import org.junit.Assert; 32 33 import java.util.concurrent.Semaphore; 34 import java.util.concurrent.TimeUnit; 35 36 @MediumTest 37 public class CarAppFocusManagerTest extends CarApiTestBase { 38 private static final String TAG = CarAppFocusManagerTest.class.getSimpleName(); 39 private CarAppFocusManager mManager; 40 41 private final LooperThread mEventThread = new LooperThread(); 42 43 @Override 44 protected void setUp() throws Exception { 45 super.setUp(); 46 mManager = (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE); 47 assertNotNull(mManager); 48 49 // Request all application focuses and abandon them to ensure no active context is present 50 // when test starts. 51 FocusOwnershipCallback owner = new FocusOwnershipCallback(); 52 mManager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner); 53 mManager.requestAppFocus(APP_FOCUS_TYPE_VOICE_COMMAND, owner); 54 mManager.abandonAppFocus(owner); 55 56 mEventThread.start(); 57 mEventThread.waitForReadyState(); 58 } 59 60 public void testSetActiveNullListener() throws Exception { 61 try { 62 mManager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, null); 63 fail(); 64 } catch (IllegalArgumentException e) { 65 // expected 66 } 67 } 68 69 public void testRegisterNull() throws Exception { 70 try { 71 mManager.addFocusListener(null, 0); 72 fail(); 73 } catch (IllegalArgumentException e) { 74 // expected 75 } 76 } 77 78 public void testRegisterUnregister() throws Exception { 79 FocusChangedListener listener = new FocusChangedListener(); 80 FocusChangedListener listener2 = new FocusChangedListener(); 81 mManager.addFocusListener(listener, 1); 82 mManager.addFocusListener(listener2, 1); 83 mManager.removeFocusListener(listener); 84 mManager.removeFocusListener(listener2); 85 mManager.removeFocusListener(listener2); // Double-unregister is OK 86 } 87 88 public void testRegisterUnregisterSpecificApp() throws Exception { 89 FocusChangedListener listener1 = new FocusChangedListener(); 90 FocusChangedListener listener2 = new FocusChangedListener(); 91 92 CarAppFocusManager manager = createManager(); 93 manager.addFocusListener(listener1, APP_FOCUS_TYPE_NAVIGATION); 94 manager.addFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION); 95 manager.addFocusListener(listener2, APP_FOCUS_TYPE_VOICE_COMMAND); 96 97 manager.removeFocusListener(listener1, APP_FOCUS_TYPE_NAVIGATION); 98 99 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 100 manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback())); 101 102 // Unregistred from nav app, no events expected. 103 assertFalse(listener1.waitForFocusChangeAndAssert( 104 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)); 105 assertTrue(listener2.waitForFocusChangeAndAssert( 106 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)); 107 108 manager.removeFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION); 109 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 110 manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, new FocusOwnershipCallback())); 111 assertFalse(listener2.waitForFocusChangeAndAssert( 112 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION, true)); 113 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 114 manager.requestAppFocus(APP_FOCUS_TYPE_VOICE_COMMAND, new FocusOwnershipCallback())); 115 assertTrue(listener2.waitForFocusChangeAndAssert( 116 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND, true)); 117 118 manager.removeFocusListener(listener2, 2); 119 manager.removeFocusListener(listener2, 2); // Double-unregister is OK 120 } 121 122 public void testFocusChange() throws Exception { 123 CarAppFocusManager manager1 = createManager(); 124 CarAppFocusManager manager2 = createManager(); 125 assertNotNull(manager2); 126 final int[] emptyFocus = new int[0]; 127 128 Assert.assertArrayEquals(emptyFocus, manager1.getActiveAppTypes()); 129 FocusChangedListener change1 = new FocusChangedListener(); 130 FocusChangedListener change2 = new FocusChangedListener(); 131 FocusOwnershipCallback owner1 = new FocusOwnershipCallback(); 132 FocusOwnershipCallback owner2 = new FocusOwnershipCallback(); 133 manager1.addFocusListener(change1, APP_FOCUS_TYPE_NAVIGATION); 134 manager1.addFocusListener(change1, APP_FOCUS_TYPE_VOICE_COMMAND); 135 manager2.addFocusListener(change2, APP_FOCUS_TYPE_NAVIGATION); 136 manager2.addFocusListener(change2, APP_FOCUS_TYPE_VOICE_COMMAND); 137 138 139 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 140 manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1)); 141 assertTrue(owner1.waitForOwnershipGrantAndAssert( 142 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)); 143 int[] expectedFocuses = new int[] {APP_FOCUS_TYPE_NAVIGATION}; 144 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 145 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 146 assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 147 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 148 assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 149 assertFalse(manager2.isOwningFocus(owner2, 150 APP_FOCUS_TYPE_VOICE_COMMAND)); 151 assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 152 APP_FOCUS_TYPE_NAVIGATION, true)); 153 assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 154 APP_FOCUS_TYPE_NAVIGATION, true)); 155 156 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 157 manager1.requestAppFocus(APP_FOCUS_TYPE_VOICE_COMMAND, owner1)); 158 assertTrue(owner1.waitForOwnershipGrantAndAssert( 159 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND)); 160 expectedFocuses = new int[] { 161 APP_FOCUS_TYPE_NAVIGATION, 162 APP_FOCUS_TYPE_VOICE_COMMAND }; 163 assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 164 assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 165 assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 166 assertFalse(manager2.isOwningFocus(owner2, 167 APP_FOCUS_TYPE_VOICE_COMMAND)); 168 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 169 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 170 assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 171 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 172 assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 173 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 174 175 // this should be no-op 176 change1.reset(); 177 change2.reset(); 178 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 179 manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner1)); 180 assertTrue(owner1.waitForOwnershipGrantAndAssert( 181 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)); 182 183 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 184 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 185 assertFalse(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 186 APP_FOCUS_TYPE_NAVIGATION, true)); 187 assertFalse(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 188 APP_FOCUS_TYPE_NAVIGATION, true)); 189 190 assertEquals(CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED, 191 manager2.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner2)); 192 assertTrue(owner2.waitForOwnershipGrantAndAssert( 193 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)); 194 195 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 196 assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 197 assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 198 assertFalse(manager2.isOwningFocus(owner2, 199 APP_FOCUS_TYPE_VOICE_COMMAND)); 200 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 201 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 202 assertTrue(owner1.waitForOwnershipLossAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 203 APP_FOCUS_TYPE_NAVIGATION)); 204 205 // no-op as it is not owning it 206 change1.reset(); 207 change2.reset(); 208 manager1.abandonAppFocus(owner1, APP_FOCUS_TYPE_NAVIGATION); 209 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 210 assertTrue(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 211 assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 212 assertFalse(manager2.isOwningFocus(owner2, 213 APP_FOCUS_TYPE_VOICE_COMMAND)); 214 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 215 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 216 217 change1.reset(); 218 change2.reset(); 219 manager1.abandonAppFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND); 220 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 221 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 222 assertTrue(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 223 assertFalse(manager2.isOwningFocus(owner2, 224 APP_FOCUS_TYPE_VOICE_COMMAND)); 225 expectedFocuses = new int[] {APP_FOCUS_TYPE_NAVIGATION}; 226 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 227 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 228 assertTrue(change2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 229 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 230 assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 231 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 232 233 change1.reset(); 234 change2.reset(); 235 manager2.abandonAppFocus(owner2, APP_FOCUS_TYPE_NAVIGATION); 236 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_NAVIGATION)); 237 assertFalse(manager1.isOwningFocus(owner1, APP_FOCUS_TYPE_VOICE_COMMAND)); 238 assertFalse(manager2.isOwningFocus(owner2, APP_FOCUS_TYPE_NAVIGATION)); 239 assertFalse(manager2.isOwningFocus(owner2, 240 APP_FOCUS_TYPE_VOICE_COMMAND)); 241 expectedFocuses = emptyFocus; 242 Assert.assertArrayEquals(expectedFocuses, manager1.getActiveAppTypes()); 243 Assert.assertArrayEquals(expectedFocuses, manager2.getActiveAppTypes()); 244 assertTrue(change1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 245 APP_FOCUS_TYPE_NAVIGATION, false)); 246 247 manager1.removeFocusListener(change1); 248 manager2.removeFocusListener(change2); 249 } 250 251 public void testFilter() throws Exception { 252 CarAppFocusManager manager1 = createManager(getContext(), mEventThread); 253 CarAppFocusManager manager2 = createManager(getContext(), mEventThread); 254 255 Assert.assertArrayEquals(new int[0], manager1.getActiveAppTypes()); 256 Assert.assertArrayEquals(new int[0], manager2.getActiveAppTypes()); 257 258 FocusChangedListener listener1 = new FocusChangedListener(); 259 FocusChangedListener listener2 = new FocusChangedListener(); 260 FocusOwnershipCallback owner = new FocusOwnershipCallback(); 261 manager1.addFocusListener(listener1, APP_FOCUS_TYPE_NAVIGATION); 262 manager1.addFocusListener(listener1, APP_FOCUS_TYPE_VOICE_COMMAND); 263 manager2.addFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION); 264 265 assertEquals(APP_FOCUS_REQUEST_SUCCEEDED, 266 manager1.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner)); 267 assertTrue(owner.waitForOwnershipGrantAndAssert( 268 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)); 269 270 assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 271 APP_FOCUS_TYPE_NAVIGATION, true)); 272 assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 273 APP_FOCUS_TYPE_NAVIGATION, true)); 274 275 listener1.reset(); 276 listener2.reset(); 277 assertEquals(APP_FOCUS_REQUEST_SUCCEEDED, 278 manager1.requestAppFocus(APP_FOCUS_TYPE_VOICE_COMMAND, owner)); 279 assertTrue(owner.waitForOwnershipGrantAndAssert( 280 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND)); 281 282 assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 283 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 284 assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 285 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 286 287 listener1.reset(); 288 listener2.reset(); 289 manager1.abandonAppFocus(owner, APP_FOCUS_TYPE_VOICE_COMMAND); 290 assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 291 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 292 assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 293 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 294 295 listener1.reset(); 296 listener2.reset(); 297 manager1.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION); 298 assertTrue(listener1.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 299 APP_FOCUS_TYPE_NAVIGATION, false)); 300 assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 301 APP_FOCUS_TYPE_NAVIGATION, false)); 302 } 303 304 private CarAppFocusManager createManager() 305 throws CarNotConnectedException, InterruptedException { 306 return createManager(getContext(), mEventThread); 307 } 308 309 private static CarAppFocusManager createManager(Context context, 310 LooperThread eventThread) throws InterruptedException, CarNotConnectedException { 311 Car car = createCar(context, eventThread); 312 CarAppFocusManager manager = (CarAppFocusManager) car.getCarManager(Car.APP_FOCUS_SERVICE); 313 assertNotNull(manager); 314 return manager; 315 } 316 317 private static Car createCar(Context context, LooperThread eventThread) 318 throws InterruptedException { 319 DefaultServiceConnectionListener connectionListener = 320 new DefaultServiceConnectionListener(); 321 Car car = Car.createCar(context, connectionListener, eventThread.mHandler); 322 assertNotNull(car); 323 car.connect(); 324 connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS); 325 return car; 326 } 327 328 public void testMultipleChangeListenersPerManager() throws Exception { 329 CarAppFocusManager manager = createManager(); 330 FocusChangedListener listener = new FocusChangedListener(); 331 FocusChangedListener listener2 = new FocusChangedListener(); 332 FocusOwnershipCallback owner = new FocusOwnershipCallback(); 333 manager.addFocusListener(listener, APP_FOCUS_TYPE_NAVIGATION); 334 manager.addFocusListener(listener, APP_FOCUS_TYPE_VOICE_COMMAND); 335 manager.addFocusListener(listener2, APP_FOCUS_TYPE_NAVIGATION); 336 337 assertEquals(APP_FOCUS_REQUEST_SUCCEEDED, 338 manager.requestAppFocus(APP_FOCUS_TYPE_NAVIGATION, owner)); 339 assertTrue(owner.waitForOwnershipGrantAndAssert( 340 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_NAVIGATION)); 341 342 assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 343 APP_FOCUS_TYPE_NAVIGATION, true)); 344 assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 345 APP_FOCUS_TYPE_NAVIGATION, true)); 346 347 listener.reset(); 348 listener2.reset(); 349 assertEquals(APP_FOCUS_REQUEST_SUCCEEDED, 350 manager.requestAppFocus(APP_FOCUS_TYPE_VOICE_COMMAND, owner)); 351 assertTrue(owner.waitForOwnershipGrantAndAssert( 352 DEFAULT_WAIT_TIMEOUT_MS, APP_FOCUS_TYPE_VOICE_COMMAND)); 353 354 assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 355 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 356 assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 357 APP_FOCUS_TYPE_VOICE_COMMAND, true)); 358 359 listener.reset(); 360 listener2.reset(); 361 manager.abandonAppFocus(owner, APP_FOCUS_TYPE_VOICE_COMMAND); 362 assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 363 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 364 assertFalse(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 365 APP_FOCUS_TYPE_VOICE_COMMAND, false)); 366 367 listener.reset(); 368 listener2.reset(); 369 manager.abandonAppFocus(owner, APP_FOCUS_TYPE_NAVIGATION); 370 assertTrue(listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 371 APP_FOCUS_TYPE_NAVIGATION, false)); 372 assertTrue(listener2.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS, 373 APP_FOCUS_TYPE_NAVIGATION, false)); 374 } 375 376 private class FocusChangedListener implements CarAppFocusManager.OnAppFocusChangedListener { 377 private volatile int mLastChangeAppType; 378 private volatile boolean mLastChangeAppActive; 379 private volatile Semaphore mChangeWait = new Semaphore(0); 380 381 boolean waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType, 382 boolean expectedAppActive) throws Exception { 383 384 if (!mChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 385 return false; 386 } 387 388 assertEquals(expectedAppType, mLastChangeAppType); 389 assertEquals(expectedAppActive, mLastChangeAppActive); 390 return true; 391 } 392 393 void reset() throws InterruptedException { 394 mLastChangeAppType = 0; 395 mLastChangeAppActive = false; 396 mChangeWait.drainPermits(); 397 } 398 399 @Override 400 public void onAppFocusChanged(int appType, boolean active) { 401 assertEventThread(); 402 mLastChangeAppType = appType; 403 mLastChangeAppActive = active; 404 mChangeWait.release(); 405 } 406 } 407 408 private class FocusOwnershipCallback 409 implements CarAppFocusManager.OnAppFocusOwnershipCallback { 410 private int mLastLossEvent; 411 private final Semaphore mLossEventWait = new Semaphore(0); 412 private int mLastGrantEvent; 413 private final Semaphore mGrantEventWait = new Semaphore(0); 414 415 boolean waitForOwnershipLossAndAssert(long timeoutMs, int expectedAppType) 416 throws Exception { 417 if (!mLossEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 418 return false; 419 } 420 assertEquals(expectedAppType, mLastLossEvent); 421 return true; 422 } 423 424 boolean waitForOwnershipGrantAndAssert(long timeoutMs, int expectedAppType) 425 throws Exception { 426 if (!mGrantEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 427 return false; 428 } 429 assertEquals(expectedAppType, mLastGrantEvent); 430 return true; 431 } 432 433 @Override 434 public void onAppFocusOwnershipLost(int appType) { 435 Log.i(TAG, "onAppFocusOwnershipLost " + appType); 436 assertEventThread(); 437 mLastLossEvent = appType; 438 mLossEventWait.release(); 439 } 440 441 @Override 442 public void onAppFocusOwnershipGranted(int appType) { 443 Log.i(TAG, "onAppFocusOwnershipGranted " + appType); 444 mLastGrantEvent = appType; 445 mGrantEventWait.release(); 446 } 447 } 448 449 private void assertEventThread() { 450 assertEquals(mEventThread, Thread.currentThread()); 451 } 452 453 private static class LooperThread extends Thread { 454 455 private final Object mReadySync = new Object(); 456 457 volatile Handler mHandler; 458 459 @Override 460 public void run() { 461 Looper.prepare(); 462 mHandler = new Handler(); 463 464 synchronized (mReadySync) { 465 mReadySync.notifyAll(); 466 } 467 468 Looper.loop(); 469 } 470 471 void waitForReadyState() throws InterruptedException { 472 synchronized (mReadySync) { 473 mReadySync.wait(DEFAULT_WAIT_TIMEOUT_MS); 474 } 475 } 476 } 477 } 478