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