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 com.android.car;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNull;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import android.car.Car;
24 import android.car.CarAppFocusManager;
25 import android.util.Log;
26 
27 import androidx.test.ext.junit.runners.AndroidJUnit4;
28 import androidx.test.filters.MediumTest;
29 
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 
33 import java.util.concurrent.Semaphore;
34 import java.util.concurrent.TimeUnit;
35 
36 @RunWith(AndroidJUnit4.class)
37 @MediumTest
38 public class AppFocusTest extends MockedCarTestBase {
39     private static final String TAG = AppFocusTest.class.getSimpleName();
40     private static final long DEFAULT_WAIT_TIMEOUT_MS = 1000;
41 
42     @Test
testFocusChange()43     public void testFocusChange() throws Exception {
44         CarAppFocusManager manager = (CarAppFocusManager) getCar().getCarManager(
45                 Car.APP_FOCUS_SERVICE);
46         FocusChangedListener listener = new FocusChangedListener();
47         FocusOwnershipCallback ownershipListener = new FocusOwnershipCallback();
48         manager.addFocusListener(listener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
49         manager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, ownershipListener);
50         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
51                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, true);
52         assertThat(manager.getAppTypeOwner(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION))
53                 .containsExactly("com.android.car.test", "com.google.android.car.kitchensink");
54         listener.resetWait();
55         manager.abandonAppFocus(ownershipListener, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);
56         listener.waitForFocusChangeAndAssert(DEFAULT_WAIT_TIMEOUT_MS,
57                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false);
58         assertNull(manager.getAppTypeOwner(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION));
59         manager.removeFocusListener(listener);
60     }
61 
62     private class FocusChangedListener implements CarAppFocusManager.OnAppFocusChangedListener {
63         private int mLastChangeAppType;
64         private boolean mLastChangeAppActive;
65         private final Semaphore mChangeWait = new Semaphore(0);
66 
waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType, boolean expectedAppActive)67         private boolean waitForFocusChangeAndAssert(long timeoutMs, int expectedAppType,
68                 boolean expectedAppActive) throws Exception {
69             if (!mChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
70                 return false;
71             }
72             assertEquals(expectedAppType, mLastChangeAppType);
73             assertEquals(expectedAppActive, mLastChangeAppActive);
74             return true;
75         }
76 
resetWait()77         private void resetWait() {
78             mChangeWait.drainPermits();
79         }
80 
81         @Override
onAppFocusChanged(int appType, boolean active)82         public void onAppFocusChanged(int appType, boolean active) {
83             Log.i(TAG, "onAppFocusChanged appType=" + appType + " active=" + active);
84             mLastChangeAppType = appType;
85             mLastChangeAppActive = active;
86             mChangeWait.release();
87         }
88     }
89 
90     private class FocusOwnershipCallback
91             implements CarAppFocusManager.OnAppFocusOwnershipCallback {
92         private int mLastLossEvent;
93         private final Semaphore mLossEventWait = new Semaphore(0);
94 
95         private int mLastGrantEvent;
96         private final Semaphore mGrantEventWait = new Semaphore(0);
97 
waitForOwnershipLossAndAssert(long timeoutMs, int expectedLossAppType)98         public boolean waitForOwnershipLossAndAssert(long timeoutMs, int expectedLossAppType)
99                 throws Exception {
100             if (!mLossEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
101                 return false;
102             }
103             assertEquals(expectedLossAppType, mLastLossEvent);
104             return true;
105         }
106 
waitForOwnershipGrantAndAssert(long timeoutMs, int expectedGrantAppType)107         public boolean waitForOwnershipGrantAndAssert(long timeoutMs, int expectedGrantAppType)
108                 throws Exception {
109             if (!mGrantEventWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
110                 return false;
111             }
112             assertEquals(expectedGrantAppType, mLastGrantEvent);
113             return true;
114         }
115 
116         @Override
onAppFocusOwnershipLost(int appType)117         public void onAppFocusOwnershipLost(int appType) {
118             Log.i(TAG, "onAppFocusOwnershipLost " + appType);
119             mLastLossEvent = appType;
120             mLossEventWait.release();
121         }
122 
123         @Override
onAppFocusOwnershipGranted(int appType)124         public void onAppFocusOwnershipGranted(int appType) {
125             Log.i(TAG, "onAppFocusOwnershipGranted " + appType);
126             mLastGrantEvent = appType;
127             mGrantEventWait.release();
128         }
129     }
130 }
131