CarVolumeServiceTest.java revision 7877faa874e502ef9a20bc9299222c718873ec91
1/* 2 * Copyright (C) 2016 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.test; 17 18import android.car.Car; 19import android.car.CarNotConnectedException; 20import android.car.media.CarAudioManager; 21import android.car.test.VehicleHalEmulator; 22import android.content.Context; 23import android.media.AudioAttributes; 24import android.media.AudioManager; 25import android.os.SystemClock; 26import android.util.Pair; 27import android.util.SparseIntArray; 28import android.view.KeyEvent; 29 30import com.android.car.vehiclenetwork.VehicleNetworkConsts; 31import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag; 32import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState; 33import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; 34import com.android.car.vehiclenetwork.VehiclePropConfigUtil; 35import com.android.car.vehiclenetwork.VehiclePropValueUtil; 36 37import java.util.ArrayList; 38import java.util.List; 39 40public class CarVolumeServiceTest extends MockedCarTestBase { 41 private static final int MIN_VOL = 1; 42 private static final int MAX_VOL = 20; 43 private static final long TIMEOUT_MS = 3000; 44 private static final long POLL_INTERVAL_MS = 50; 45 46 private static final int[] LOGICAL_STREAMS = { 47 AudioManager.STREAM_VOICE_CALL, 48 AudioManager.STREAM_SYSTEM, 49 AudioManager.STREAM_RING, 50 AudioManager.STREAM_MUSIC, 51 AudioManager.STREAM_ALARM, 52 AudioManager.STREAM_NOTIFICATION, 53 AudioManager.STREAM_DTMF, 54 }; 55 56 private CarAudioManager mCarAudioManager; 57 private AudioManager mAudioManager; 58 59 @Override 60 protected synchronized void setUp() throws Exception { 61 super.setUp(); 62 // AudioManager should be created in main thread to get focus event. :( 63 runOnMainSync(new Runnable() { 64 @Override 65 public void run() { 66 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 67 } 68 }); 69 70 List<Integer> mins = new ArrayList<>(); 71 List<Integer> maxs = new ArrayList<>(); 72 mins.add(MIN_VOL); 73 mins.add(MIN_VOL); 74 75 maxs.add(MAX_VOL); 76 maxs.add(MAX_VOL); 77 78 // TODO: add tests for audio context supported cases. 79 startVolumeEmulation(0 /*supported audio context*/, maxs, mins); 80 mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE); 81 } 82 83 public void testVolumeLimits() throws Exception { 84 for (int stream : LOGICAL_STREAMS) { 85 assertEquals(MIN_VOL, mCarAudioManager.getStreamMinVolume(stream)); 86 assertEquals(MAX_VOL, mCarAudioManager.getStreamMaxVolume(stream)); 87 } 88 } 89 90 public void testVolumeSet() { 91 try { 92 int callVol = 10; 93 int musicVol = 15; 94 mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0); 95 mCarAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, callVol, 0); 96 97 volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol), 98 createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol)); 99 100 musicVol = MAX_VOL + 1; 101 mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0); 102 103 volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, MAX_VOL), 104 createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol)); 105 } catch (CarNotConnectedException e) { 106 fail("Car not connected"); 107 } 108 } 109 110 public void testVolumeKeys() throws Exception { 111 try { 112 int musicVol = 10; 113 mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0); 114 int callVol = 12; 115 mCarAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, callVol, 0); 116 117 CarAudioFocusTest.AudioFocusListener listenerMusic = 118 new CarAudioFocusTest.AudioFocusListener(); 119 int res = mAudioManager.requestAudioFocus(listenerMusic, 120 AudioManager.STREAM_MUSIC, 121 AudioManager.AUDIOFOCUS_GAIN); 122 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 123 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 124 mAudioFocusPropertyHandler.sendAudioFocusState( 125 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN, 126 request[1], 127 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG); 128 129 130 assertEquals(musicVol, mCarAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)); 131 sendVolumeKey(true /*vol up*/); 132 musicVol++; 133 volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol)); 134 135 // call start 136 CarAudioFocusTest.AudioFocusListener listenerCall = new 137 CarAudioFocusTest.AudioFocusListener(); 138 AudioAttributes callAttrib = (new AudioAttributes.Builder()). 139 setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION). 140 build(); 141 mAudioManager.requestAudioFocus(listenerCall, callAttrib, 142 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0); 143 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 144 mAudioFocusPropertyHandler.sendAudioFocusState( 145 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN, request[1], 146 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG); 147 148 sendVolumeKey(true /*vol up*/); 149 callVol++; 150 volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol), 151 createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol)); 152 } catch (CarNotConnectedException | InterruptedException e) { 153 fail(e.toString()); 154 } 155 } 156 157 private Pair<Integer, Integer> createStreamVolPair(int stream, int vol) { 158 return new Pair<>(stream, vol); 159 } 160 161 private void volumeVerificationPoll(Pair<Integer, Integer>... expectedStreamVolPairs) { 162 boolean isVolExpected = false; 163 int timeElapsedMs = 0; 164 try { 165 while (!isVolExpected && timeElapsedMs <= TIMEOUT_MS) { 166 Thread.sleep(POLL_INTERVAL_MS); 167 isVolExpected = true; 168 for (Pair<Integer, Integer> vol : expectedStreamVolPairs) { 169 if (mCarAudioManager.getStreamVolume(vol.first) != vol.second) { 170 isVolExpected = false; 171 break; 172 } 173 } 174 timeElapsedMs += POLL_INTERVAL_MS; 175 } 176 assertEquals(isVolExpected, true); 177 } catch (InterruptedException | CarNotConnectedException e) { 178 fail(e.toString()); 179 } 180 } 181 182 private class SingleChannelVolumeHandler implements 183 VehicleHalEmulator.VehicleHalPropertyHandler { 184 private final List<Integer> mMins; 185 private final List<Integer> mMaxs; 186 private final SparseIntArray mCurrent; 187 188 public SingleChannelVolumeHandler(List<Integer> mins, List<Integer> maxs) { 189 assertEquals(mins.size(), maxs.size()); 190 mMins = mins; 191 mMaxs = maxs; 192 mCurrent = new SparseIntArray(mMins.size()); 193 // initialize the vol to be the min volume. 194 for (int i = 0; i < mMins.size(); i++) { 195 mCurrent.put(i, mMins.get(i)); 196 } 197 } 198 199 @Override 200 public void onPropertySet(VehiclePropValue value) { 201 int stream = value.getInt32Values( 202 VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM); 203 int volume = value.getInt32Values( 204 VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_VOLUME); 205 int state = value.getInt32Values( 206 VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STATE); 207 208 int[] values = {stream, volume, state}; 209 VehiclePropValue injectValue = VehiclePropValueUtil.createIntVectorValue( 210 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, values, 211 SystemClock.elapsedRealtimeNanos()); 212 mCurrent.put(stream, volume); 213 getVehicleHalEmulator().injectEvent(injectValue); 214 } 215 216 @Override 217 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 218 int stream = value.getInt32Values( 219 VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM); 220 221 int volume = mCurrent.get(stream); 222 int[] values = {stream, volume, 0}; 223 VehiclePropValue propValue = VehiclePropValueUtil.createIntVectorValue( 224 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, values, 225 SystemClock.elapsedRealtimeNanos()); 226 return propValue; 227 } 228 229 @Override 230 public void onPropertySubscribe(int property, float sampleRate, int zones) { 231 } 232 233 @Override 234 public void onPropertyUnsubscribe(int property) { 235 } 236 } 237 238 private final CarAudioFocusTest.FocusPropertyHandler mAudioFocusPropertyHandler = 239 new CarAudioFocusTest.FocusPropertyHandler(this); 240 241 private final VehicleHalEmulator.VehicleHalPropertyHandler mAudioRoutingPolicyPropertyHandler = 242 new VehicleHalEmulator.VehicleHalPropertyHandler() { 243 @Override 244 public void onPropertySet(VehiclePropValue value) { 245 //TODO 246 } 247 248 @Override 249 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 250 fail("cannot get"); 251 return null; 252 } 253 254 @Override 255 public void onPropertySubscribe(int property, float sampleRate, int zones) { 256 fail("cannot subscribe"); 257 } 258 259 @Override 260 public void onPropertyUnsubscribe(int property) { 261 fail("cannot unsubscribe"); 262 } 263 }; 264 265 private final VehicleHalEmulator.VehicleHalPropertyHandler mHWKeyHandler = 266 new VehicleHalEmulator.VehicleHalPropertyHandler() { 267 @Override 268 public void onPropertySet(VehiclePropValue value) { 269 //TODO 270 } 271 272 @Override 273 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 274 int[] values = {0, 0, 0, 0 }; 275 return VehiclePropValueUtil.createIntVectorValue( 276 VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, values, 277 SystemClock.elapsedRealtimeNanos()); 278 } 279 280 @Override 281 public void onPropertySubscribe(int property, float sampleRate, int zones) { 282 // 283 } 284 285 @Override 286 public void onPropertyUnsubscribe(int property) { 287 // 288 } 289 }; 290 291 private void startVolumeEmulation(int supportedAudioVolumeContext, 292 List<Integer> maxs, List<Integer> mins) { 293 SingleChannelVolumeHandler singleChannelVolumeHandler = 294 new SingleChannelVolumeHandler(mins, maxs); 295 int zones = (1<<maxs.size()) - 1; 296 getVehicleHalEmulator().addProperty( 297 VehiclePropConfigUtil.getBuilder(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, 298 VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE, 299 VehicleNetworkConsts.VehiclePropChangeMode 300 .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE, 301 VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC3, 302 VehicleNetworkConsts.VehiclePermissionModel 303 .VEHICLE_PERMISSION_SYSTEM_APP_ONLY, 304 supportedAudioVolumeContext /*configFlags*/, 305 0 /*sampleRateMax*/, 0 /*sampleRateMin*/, 306 maxs, mins).setZones(zones).build(), 307 singleChannelVolumeHandler); 308 309 getVehicleHalEmulator().addProperty( 310 VehiclePropConfigUtil.getBuilder( 311 VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, 312 VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ, 313 VehicleNetworkConsts.VehiclePropChangeMode 314 .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE, 315 VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4, 316 VehicleNetworkConsts.VehiclePermissionModel 317 .VEHICLE_PERMISSION_SYSTEM_APP_ONLY, 318 0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(), 319 mHWKeyHandler); 320 321 getVehicleHalEmulator().addProperty( 322 VehiclePropConfigUtil.getBuilder( 323 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, 324 VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE, 325 VehicleNetworkConsts.VehiclePropChangeMode 326 .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE, 327 VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4, 328 VehicleNetworkConsts.VehiclePermissionModel 329 .VEHICLE_PERMISSION_SYSTEM_APP_ONLY, 330 0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(), 331 mAudioFocusPropertyHandler); 332 getVehicleHalEmulator().addProperty( 333 VehiclePropConfigUtil.getBuilder( 334 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY, 335 VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE, 336 VehicleNetworkConsts.VehiclePropChangeMode 337 .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE, 338 VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2, 339 VehicleNetworkConsts.VehiclePermissionModel 340 .VEHICLE_PERMISSION_SYSTEM_APP_ONLY, 341 0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(), 342 mAudioRoutingPolicyPropertyHandler); 343 344 getVehicleHalEmulator().addStaticProperty( 345 VehiclePropConfigUtil.createStaticStringProperty( 346 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT), 347 VehiclePropValueUtil.createIntValue( 348 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT, 1, 0)); 349 350 getVehicleHalEmulator().start(); 351 } 352 353 public void sendVolumeKey(boolean volUp) { 354 int[] values = { 355 VehicleNetworkConsts.VehicleHwKeyInputAction.VEHICLE_HW_KEY_INPUT_ACTION_DOWN, 356 volUp ? KeyEvent.KEYCODE_VOLUME_UP : KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0 }; 357 358 VehiclePropValue injectValue = VehiclePropValueUtil.createIntVectorValue( 359 VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, values, 360 SystemClock.elapsedRealtimeNanos()); 361 362 getVehicleHalEmulator().injectEvent(injectValue); 363 364 int[] upValues = { 365 VehicleNetworkConsts.VehicleHwKeyInputAction.VEHICLE_HW_KEY_INPUT_ACTION_UP, 366 volUp ? KeyEvent.KEYCODE_VOLUME_UP : KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0 }; 367 368 injectValue = VehiclePropValueUtil.createIntVectorValue( 369 VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, upValues, 370 SystemClock.elapsedRealtimeNanos()); 371 372 getVehicleHalEmulator().injectEvent(injectValue); 373 } 374} 375