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