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 17 package com.android.car; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import android.car.Car; 23 import android.car.CarProjectionManager; 24 import android.hardware.automotive.vehicle.VehicleDisplay; 25 import android.hardware.automotive.vehicle.VehicleHwKeyInputAction; 26 import android.hardware.automotive.vehicle.VehiclePropValue; 27 import android.hardware.automotive.vehicle.VehicleProperty; 28 import android.hardware.automotive.vehicle.VehiclePropertyAccess; 29 import android.os.SystemClock; 30 import android.util.Log; 31 import android.view.KeyEvent; 32 33 import androidx.test.ext.junit.runners.AndroidJUnit4; 34 import androidx.test.filters.MediumTest; 35 36 import com.android.car.hal.test.AidlMockedVehicleHal.VehicleHalPropertyHandler; 37 import com.android.car.hal.test.AidlVehiclePropValueBuilder; 38 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.util.HashMap; 43 import java.util.concurrent.Semaphore; 44 import java.util.concurrent.TimeUnit; 45 46 @RunWith(AndroidJUnit4.class) 47 @MediumTest 48 public class CarProjectionManagerTest extends MockedCarTestBase { 49 private static final String TAG = CarProjectionManagerTest.class.getSimpleName(); 50 51 private final Semaphore mLongAvailable = new Semaphore(0); 52 private final Semaphore mAvailable = new Semaphore(0); 53 54 private final CarProjectionManager.CarProjectionListener mListener = 55 new CarProjectionManager.CarProjectionListener() { 56 @Override 57 public void onVoiceAssistantRequest(boolean fromLongPress) { 58 if (fromLongPress) { 59 mLongAvailable.release(); 60 } else { 61 mAvailable.release(); 62 } 63 } 64 }; 65 66 private CarProjectionManager mManager; 67 68 @Override configureMockedHal()69 protected void configureMockedHal() { 70 addAidlProperty(VehicleProperty.HW_KEY_INPUT, new PropertyHandler()) 71 .setAccess(VehiclePropertyAccess.READ); 72 } 73 74 @Override setUp()75 public void setUp() throws Exception { 76 super.setUp(); 77 mManager = (CarProjectionManager) getCar().getCarManager(Car.PROJECTION_SERVICE); 78 } 79 80 @Test testShortPressListener()81 public void testShortPressListener() throws Exception { 82 mManager.registerProjectionListener( 83 mListener, 84 CarProjectionManager.PROJECTION_VOICE_SEARCH); 85 assertEquals(0, mAvailable.availablePermits()); 86 assertEquals(0, mLongAvailable.availablePermits()); 87 sendVoiceKey(false); 88 assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS)); 89 assertEquals(0, mLongAvailable.availablePermits()); 90 } 91 92 @Test testLongPressListener()93 public void testLongPressListener() throws Exception { 94 mManager.registerProjectionListener( 95 mListener, 96 CarProjectionManager.PROJECTION_LONG_PRESS_VOICE_SEARCH); 97 assertEquals(0, mLongAvailable.availablePermits()); 98 assertEquals(0, mAvailable.availablePermits()); 99 sendVoiceKey(true); 100 assertTrue(mLongAvailable.tryAcquire(2L, TimeUnit.SECONDS)); 101 assertEquals(0, mAvailable.availablePermits()); 102 } 103 104 @Test testMixedPressListener()105 public void testMixedPressListener() throws Exception { 106 mManager.registerProjectionListener( 107 mListener, 108 CarProjectionManager.PROJECTION_LONG_PRESS_VOICE_SEARCH 109 | CarProjectionManager.PROJECTION_VOICE_SEARCH); 110 assertEquals(0, mLongAvailable.availablePermits()); 111 assertEquals(0, mAvailable.availablePermits()); 112 sendVoiceKey(true); 113 assertTrue(mLongAvailable.tryAcquire(2L, TimeUnit.SECONDS)); 114 assertEquals(0, mAvailable.availablePermits()); 115 116 assertEquals(0, mLongAvailable.availablePermits()); 117 assertEquals(0, mAvailable.availablePermits()); 118 sendVoiceKey(false); 119 assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS)); 120 assertEquals(0, mLongAvailable.availablePermits()); 121 } 122 sendVoiceKey(boolean isLong)123 public void sendVoiceKey(boolean isLong) throws InterruptedException { 124 int[] values = { 125 VehicleHwKeyInputAction.ACTION_DOWN, 126 KeyEvent.KEYCODE_VOICE_ASSIST, 127 VehicleDisplay.MAIN, 128 /* no indent count */ 129 }; 130 131 VehiclePropValue injectValue = 132 AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT) 133 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 134 .addIntValues(values) 135 .build(); 136 137 getAidlMockedVehicleHal().injectEvent(injectValue); 138 139 if (isLong) { 140 Thread.sleep(1200); // Long press is > 1s. 141 } 142 143 int[] upValues = { 144 VehicleHwKeyInputAction.ACTION_UP, 145 KeyEvent.KEYCODE_VOICE_ASSIST, 146 VehicleDisplay.MAIN, 147 /* no indent count */ 148 }; 149 150 injectValue = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HW_KEY_INPUT) 151 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 152 .addIntValues(upValues) 153 .build(); 154 155 getAidlMockedVehicleHal().injectEvent(injectValue); 156 } 157 158 159 private class PropertyHandler implements VehicleHalPropertyHandler { 160 HashMap<Integer, VehiclePropValue> mMap = new HashMap<>(); 161 162 @Override onPropertySet(VehiclePropValue value)163 public synchronized void onPropertySet(VehiclePropValue value) { 164 Log.d(TAG, "onPropertySet:" + value); 165 mMap.put(value.prop, value); 166 } 167 168 @Override onPropertyGet(VehiclePropValue value)169 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 170 Log.d(TAG, "onPropertyGet:" + value); 171 VehiclePropValue currentValue = mMap.get(value.prop); 172 // VNS will call get method when subscribe is called, just return empty value. 173 return currentValue != null ? currentValue : value; 174 } 175 176 @Override onPropertySubscribe(int property, float sampleRate)177 public synchronized void onPropertySubscribe(int property, float sampleRate) { 178 Log.d(TAG, "onPropertySubscribe property " + property + " sampleRate " + sampleRate); 179 } 180 181 @Override onPropertyUnsubscribe(int property)182 public synchronized void onPropertyUnsubscribe(int property) { 183 Log.d(TAG, "onPropertyUnSubscribe property " + property); 184 } 185 } 186 } 187