Home | History | Annotate | Download | only in apitest
      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