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.test; 17 18import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_FOCUS; 19import static com.android.car.test.AudioTestUtils.doRequestFocus; 20 21import android.car.Car; 22import android.car.media.CarAudioManager; 23import android.content.Context; 24import android.hardware.automotive.vehicle.V2_0.VehicleAudioContextFlag; 25import android.hardware.automotive.vehicle.V2_0.VehicleAudioExtFocusFlag; 26import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusIndex; 27import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusRequest; 28import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusState; 29import android.hardware.automotive.vehicle.V2_0.VehicleAudioStream; 30import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 31import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 32import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 33import android.media.AudioAttributes; 34import android.media.AudioManager; 35import android.os.SystemClock; 36import android.test.suitebuilder.annotation.MediumTest; 37import android.util.Log; 38 39import com.google.android.collect.Lists; 40 41import com.android.car.vehiclehal.VehiclePropValueBuilder; 42import com.android.car.vehiclehal.test.MockedVehicleHal.FailingPropertyHandler; 43import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 44 45import java.util.ArrayList; 46import java.util.concurrent.Semaphore; 47import java.util.concurrent.TimeUnit; 48 49// TODO: refactor all CarAudio*Test classes, they have a lot of common logic. 50@MediumTest 51public class CarAudioFocusTest extends MockedCarTestBase { 52 private static final String TAG = CarAudioFocusTest.class.getSimpleName(); 53 54 private static final long TIMEOUT_MS = 3000; 55 56 private final VehicleHalPropertyHandler mAudioRoutingPolicyPropertyHandler = 57 new FailingPropertyHandler() { 58 @Override 59 public void onPropertySet(VehiclePropValue value) { 60 //TODO 61 } 62 }; 63 64 private final FocusPropertyHandler mAudioFocusPropertyHandler = 65 new FocusPropertyHandler(this); 66 67 private AudioManager mAudioManager; 68 69 @Override 70 protected synchronized void configureMockedHal() { 71 addProperty(VehicleProperty.AUDIO_ROUTING_POLICY, mAudioRoutingPolicyPropertyHandler) 72 .setAccess(VehiclePropertyAccess.WRITE); 73 74 addProperty(VehicleProperty.AUDIO_FOCUS, mAudioFocusPropertyHandler); 75 76 addStaticProperty(VehicleProperty.AUDIO_HW_VARIANT, 77 VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_HW_VARIANT) 78 .addIntValue(-1) 79 .build()) 80 .setConfigArray(Lists.newArrayList(0)); 81 } 82 83 @Override 84 protected void setUp() throws Exception { 85 super.setUp(); 86 // AudioManager should be created in main thread to get focus event. :( 87 runOnMainSync(new Runnable() { 88 @Override 89 public void run() { 90 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 91 } 92 }); 93 } 94 95 public void testMediaGainFocus() throws Exception { 96 //TODO update this to check config 97 checkSingleRequestRelease( 98 AudioManager.STREAM_MUSIC, 99 AudioManager.AUDIOFOCUS_GAIN, 100 VehicleAudioStream.STREAM0, 101 VehicleAudioContextFlag.MUSIC_FLAG); 102 } 103 104 public void testMediaGainTransientFocus() throws Exception { 105 checkSingleRequestRelease( 106 AudioManager.STREAM_MUSIC, 107 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, 108 VehicleAudioStream.STREAM0, 109 VehicleAudioContextFlag.MUSIC_FLAG); 110 } 111 112 public void testMediaGainTransientMayDuckFocus() throws Exception { 113 checkSingleRequestRelease( 114 AudioManager.STREAM_MUSIC, 115 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 116 VehicleAudioStream.STREAM0, 117 VehicleAudioContextFlag.MUSIC_FLAG); 118 } 119 120 public void testAlarmGainTransientFocus() throws Exception { 121 checkSingleRequestRelease( 122 AudioManager.STREAM_ALARM, 123 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, 124 VehicleAudioStream.STREAM1, 125 VehicleAudioContextFlag.ALARM_FLAG); 126 } 127 128 public void testAlarmGainTransientMayDuckFocus() throws Exception { 129 checkSingleRequestRelease( 130 AudioManager.STREAM_ALARM, 131 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 132 VehicleAudioStream.STREAM1, 133 VehicleAudioContextFlag.ALARM_FLAG); 134 } 135 136 public void testMediaNavFocus() throws Exception { 137 //music start 138 AudioFocusListener listenerMusic = new AudioFocusListener(); 139 int res = doRequestFocus(mAudioManager, listenerMusic, 140 AudioManager.STREAM_MUSIC, 141 AudioManager.AUDIOFOCUS_GAIN); 142 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 143 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 144 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 145 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 146 assertEquals(0, request[2]); 147 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 148 mAudioFocusPropertyHandler.sendAudioFocusState( 149 VehicleAudioFocusState.STATE_GAIN, 150 request[1], 151 VehicleAudioExtFocusFlag.NONE_FLAG); 152 153 // nav guidance start 154 AudioFocusListener listenerNav = new AudioFocusListener(); 155 AudioAttributes navAttrib = (new AudioAttributes.Builder()). 156 setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION). 157 setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE). 158 build(); 159 doRequestFocus(mAudioManager, listenerNav, navAttrib, 160 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 161 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 162 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 163 assertEquals(0x3, request[1]); 164 assertEquals(0, request[2]); 165 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG | 166 VehicleAudioContextFlag.NAVIGATION_FLAG, request[3]); 167 mAudioFocusPropertyHandler.sendAudioFocusState( 168 VehicleAudioFocusState.STATE_GAIN, request[1], 169 VehicleAudioExtFocusFlag.NONE_FLAG); 170 171 // nav guidance done 172 mAudioManager.abandonAudioFocus(listenerNav); 173 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 174 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 175 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 176 assertEquals(0, request[2]); 177 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 178 mAudioFocusPropertyHandler.sendAudioFocusState( 179 VehicleAudioFocusState.STATE_GAIN, request[1], 180 VehicleAudioExtFocusFlag.NONE_FLAG); 181 182 // music done 183 mAudioManager.abandonAudioFocus(listenerMusic); 184 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 185 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 186 assertEquals(0, request[1]); 187 assertEquals(0, request[2]); 188 assertEquals(0, request[3]); 189 mAudioFocusPropertyHandler.sendAudioFocusState( 190 VehicleAudioFocusState.STATE_LOSS, request[1], 191 VehicleAudioExtFocusFlag.NONE_FLAG); 192 } 193 194 public void testMediaExternalMediaNavFocus() throws Exception { 195 // android music 196 AudioFocusListener listenerMusic = new AudioFocusListener(); 197 int res = doRequestFocus(mAudioManager, listenerMusic, 198 AudioManager.STREAM_MUSIC, 199 AudioManager.AUDIOFOCUS_GAIN); 200 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 201 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 202 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 203 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 204 assertEquals(0, request[2]); 205 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 206 mAudioFocusPropertyHandler.sendAudioFocusState( 207 VehicleAudioFocusState.STATE_GAIN, 208 request[1], 209 VehicleAudioExtFocusFlag.NONE_FLAG); 210 211 // car plays external media (=outside Android) 212 mAudioFocusPropertyHandler.sendAudioFocusState( 213 VehicleAudioFocusState.STATE_LOSS, 214 0, 215 VehicleAudioExtFocusFlag.PERMANENT_FLAG); 216 int focusChange = listenerMusic.waitAndGetFocusChange(TIMEOUT_MS); 217 assertEquals(AudioManager.AUDIOFOCUS_LOSS, focusChange); 218 219 // nav guidance start 220 AudioFocusListener listenerNav = new AudioFocusListener(); 221 AudioAttributes navAttrib = (new AudioAttributes.Builder()). 222 setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION). 223 setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE). 224 build(); 225 doRequestFocus(mAudioManager, listenerNav, navAttrib, 226 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 227 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 228 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK, 229 request[0]); 230 assertEquals(0x1 << VehicleAudioStream.STREAM1, request[1]); 231 assertEquals(0, request[2]); 232 assertEquals(VehicleAudioContextFlag.NAVIGATION_FLAG, request[3]); 233 mAudioFocusPropertyHandler.sendAudioFocusState( 234 VehicleAudioFocusState.STATE_GAIN_TRANSIENT, 235 0x1 << VehicleAudioStream.STREAM1, 236 VehicleAudioExtFocusFlag.PERMANENT_FLAG); 237 238 // nav guidance ends 239 mAudioManager.abandonAudioFocus(listenerNav); 240 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 241 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 242 assertEquals(0, request[1]); 243 assertEquals(0, request[2]); 244 assertEquals(0, request[3]); 245 mAudioFocusPropertyHandler.sendAudioFocusState( 246 VehicleAudioFocusState.STATE_LOSS, 247 0, 248 VehicleAudioExtFocusFlag.PERMANENT_FLAG); 249 250 // now ends external play 251 mAudioFocusPropertyHandler.sendAudioFocusState( 252 VehicleAudioFocusState.STATE_LOSS, 253 0, 254 0); 255 mAudioManager.abandonAudioFocus(listenerMusic); 256 //TODO how to check this? 257 } 258 259 public void testMediaExternalRadioNavMediaFocus() throws Exception { 260 // android music 261 AudioFocusListener listenerMusic = new AudioFocusListener(); 262 int res = doRequestFocus(mAudioManager, listenerMusic, 263 AudioManager.STREAM_MUSIC, 264 AudioManager.AUDIOFOCUS_GAIN); 265 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 266 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 267 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 268 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 269 assertEquals(0, request[2]); 270 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 271 mAudioFocusPropertyHandler.sendAudioFocusState( 272 VehicleAudioFocusState.STATE_GAIN, 273 request[1], 274 VehicleAudioExtFocusFlag.NONE_FLAG); 275 276 // android radio 277 AudioFocusListener listenerRadio = new AudioFocusListener(); 278 CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager( 279 Car.AUDIO_SERVICE); 280 assertNotNull(carAudioManager); 281 AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage( 282 CarAudioManager.CAR_AUDIO_USAGE_RADIO); 283 res = doRequestFocus(mAudioManager, listenerRadio, 284 radioAttributes, AudioManager.AUDIOFOCUS_GAIN); 285 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 286 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 287 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 288 assertEquals(0, request[1]); 289 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 290 request[2]); 291 assertEquals(VehicleAudioContextFlag.RADIO_FLAG, request[3]); 292 mAudioFocusPropertyHandler.sendAudioFocusState( 293 VehicleAudioFocusState.STATE_GAIN, 294 0, 295 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 296 297 // nav guidance start 298 AudioFocusListener listenerNav = new AudioFocusListener(); 299 AudioAttributes navAttrib = (new AudioAttributes.Builder()). 300 setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION). 301 setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE). 302 build(); 303 res = doRequestFocus(mAudioManager, listenerNav, navAttrib, 304 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 305 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 306 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, 307 request[0]); 308 assertEquals(0x1 << VehicleAudioStream.STREAM1, request[1]); 309 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 310 request[2]); 311 assertEquals(VehicleAudioContextFlag.NAVIGATION_FLAG | 312 VehicleAudioContextFlag.RADIO_FLAG, request[3]); 313 mAudioFocusPropertyHandler.sendAudioFocusState( 314 VehicleAudioFocusState.STATE_GAIN, 315 0x1 << VehicleAudioStream.STREAM1, 316 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 317 318 // nav guidance ends 319 mAudioManager.abandonAudioFocus(listenerNav); 320 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 321 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, 322 request[0]); 323 assertEquals(0, request[1]); 324 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 325 request[2]); 326 assertEquals(VehicleAudioContextFlag.RADIO_FLAG, request[3]); 327 mAudioFocusPropertyHandler.sendAudioFocusState( 328 VehicleAudioFocusState.STATE_GAIN, 329 0, 330 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 331 332 // ends radio. music will get the focus GAIN. 333 // Music app is supposed to stop and release focus when it has lost focus, but here just 334 // check if focus is working. 335 mAudioManager.abandonAudioFocus(listenerRadio); 336 listenerMusic.waitForFocus(TIMEOUT_MS, AudioManager.AUDIOFOCUS_GAIN); 337 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 338 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 339 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 340 assertEquals(0, request[2]); 341 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 342 mAudioFocusPropertyHandler.sendAudioFocusState( 343 VehicleAudioFocusState.STATE_GAIN, 344 0x1 << VehicleAudioStream.STREAM0, 345 0); 346 347 // now music release focus. 348 mAudioManager.abandonAudioFocus(listenerMusic); 349 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 350 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 351 assertEquals(0, request[1]); 352 assertEquals(0, request[2]); 353 assertEquals(0, request[3]); 354 mAudioFocusPropertyHandler.sendAudioFocusState( 355 VehicleAudioFocusState.STATE_LOSS, 356 0, 357 VehicleAudioExtFocusFlag.NONE_FLAG); 358 } 359 360 private void checkSingleRequestRelease(int streamType, int androidFocus, int streamNumber, 361 int context) 362 throws Exception { 363 AudioFocusListener lister = new AudioFocusListener(); 364 int res = doRequestFocus(mAudioManager, lister, 365 streamType, 366 androidFocus); 367 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 368 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 369 int expectedRequest = VehicleAudioFocusRequest.REQUEST_RELEASE; 370 int response = VehicleAudioFocusState.STATE_LOSS; 371 switch (androidFocus) { 372 case AudioManager.AUDIOFOCUS_GAIN: 373 expectedRequest = VehicleAudioFocusRequest.REQUEST_GAIN; 374 response = VehicleAudioFocusState.STATE_GAIN; 375 break; 376 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: 377 expectedRequest = 378 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT; 379 response = VehicleAudioFocusState.STATE_GAIN_TRANSIENT; 380 break; 381 case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 382 expectedRequest = 383 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK; 384 response = VehicleAudioFocusState.STATE_GAIN_TRANSIENT; 385 break; 386 } 387 assertEquals(expectedRequest, request[0]); 388 assertEquals(0x1 << streamNumber, request[1]); 389 assertEquals(0, request[2]); 390 assertEquals(context, request[3]); 391 mAudioFocusPropertyHandler.sendAudioFocusState( 392 response, 393 request[1], 394 VehicleAudioExtFocusFlag.NONE_FLAG); 395 mAudioManager.abandonAudioFocus(lister); 396 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 397 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 398 assertEquals(0, request[1]); 399 assertEquals(0, request[2]); 400 assertEquals(0, request[3]); 401 mAudioFocusPropertyHandler.sendAudioFocusState( 402 VehicleAudioFocusState.STATE_LOSS, 403 request[1], 404 VehicleAudioExtFocusFlag.NONE_FLAG); 405 } 406 407 public void testRadioMute() throws Exception { 408 doTestMediaMute(CarAudioManager.CAR_AUDIO_USAGE_RADIO, 409 0, 410 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 411 VehicleAudioContextFlag.RADIO_FLAG); 412 } 413 414 public void testMusicMute() throws Exception { 415 doTestMediaMute(CarAudioManager.CAR_AUDIO_USAGE_MUSIC, 416 0x1, 417 0, 418 VehicleAudioContextFlag.MUSIC_FLAG); 419 } 420 421 private void doTestMediaMute(int mediaUsage, int primaryStream, int extFocusFlag, 422 int mediaContext) throws Exception { 423 // android radio 424 AudioFocusListener listenerMedia = new AudioFocusListener(); 425 CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager( 426 Car.AUDIO_SERVICE); 427 assertNotNull(carAudioManager); 428 AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage(mediaUsage); 429 Log.i(TAG, "request media Focus"); 430 int res = doRequestFocus(mAudioManager, listenerMedia, 431 radioAttributes, AudioManager.AUDIOFOCUS_GAIN); 432 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 433 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 434 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 435 assertEquals(primaryStream, request[1]); 436 assertEquals(extFocusFlag, request[2]); 437 assertEquals(mediaContext, request[3]); 438 mAudioFocusPropertyHandler.sendAudioFocusState( 439 VehicleAudioFocusState.STATE_GAIN, 440 primaryStream, 441 extFocusFlag); 442 // now mute it. 443 assertFalse(carAudioManager.isMediaMuted()); 444 Log.i(TAG, "mute media"); 445 assertTrue(carAudioManager.setMediaMute(true)); 446 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 447 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT, 448 request[0]); 449 assertEquals(0, request[1]); 450 assertEquals(VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG, 451 request[2]); 452 assertEquals(0, request[3]); 453 mAudioFocusPropertyHandler.sendAudioFocusState( 454 VehicleAudioFocusState.STATE_GAIN, 455 0, 456 VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG); 457 assertTrue(carAudioManager.isMediaMuted()); 458 // nav guidance on top of it 459 AudioFocusListener listenerNav = new AudioFocusListener(); 460 AudioAttributes navAttrib = (new AudioAttributes.Builder()). 461 setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION). 462 setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE). 463 build(); 464 Log.i(TAG, "request nav Focus"); 465 res = doRequestFocus(mAudioManager, listenerNav, navAttrib, 466 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 467 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 468 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK, 469 request[0]); 470 assertEquals(0x1 << VehicleAudioStream.STREAM1, request[1]); 471 assertEquals(VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG, 472 request[2]); 473 assertEquals(VehicleAudioContextFlag.NAVIGATION_FLAG, request[3]); 474 assertTrue(carAudioManager.isMediaMuted()); 475 mAudioFocusPropertyHandler.sendAudioFocusState( 476 VehicleAudioFocusState.STATE_GAIN, 477 0x1 << VehicleAudioStream.STREAM1, 478 VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG); 479 assertTrue(carAudioManager.isMediaMuted()); 480 // nav guidance ends 481 mAudioManager.abandonAudioFocus(listenerNav); 482 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 483 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT, 484 request[0]); 485 assertEquals(0, request[1]); 486 assertEquals(VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG, 487 request[2]); 488 assertEquals(0, request[3]); 489 assertTrue(carAudioManager.isMediaMuted()); 490 mAudioFocusPropertyHandler.sendAudioFocusState( 491 VehicleAudioFocusState.STATE_GAIN, 492 0, 493 VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG); 494 // now unmute it. radio should resume. 495 assertTrue(carAudioManager.isMediaMuted()); 496 assertFalse(carAudioManager.setMediaMute(false)); 497 assertFalse(carAudioManager.isMediaMuted()); 498 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 499 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 500 assertEquals(primaryStream, request[1]); 501 assertEquals(extFocusFlag, 502 request[2]); 503 assertEquals(mediaContext, request[3]); 504 assertFalse(carAudioManager.isMediaMuted()); 505 mAudioFocusPropertyHandler.sendAudioFocusState( 506 VehicleAudioFocusState.STATE_GAIN, 507 primaryStream, 508 extFocusFlag); 509 assertFalse(carAudioManager.isMediaMuted()); 510 // release focus 511 mAudioManager.abandonAudioFocus(listenerMedia); 512 } 513 514 static class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener { 515 private final Semaphore mFocusChangeWait = new Semaphore(0); 516 private int mLastFocusChange; 517 518 int waitAndGetFocusChange(long timeoutMs) throws Exception { 519 if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 520 fail("timeout waiting for focus change"); 521 } 522 return mLastFocusChange; 523 } 524 525 void waitForFocus(long timeoutMs, int expectedFocus) throws Exception { 526 while (mLastFocusChange != expectedFocus) { 527 if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 528 fail("timeout waiting for focus change"); 529 } 530 } 531 } 532 533 @Override 534 public void onAudioFocusChange(int focusChange) { 535 mLastFocusChange = focusChange; 536 mFocusChangeWait.release(); 537 } 538 } 539 540 static class FocusPropertyHandler implements VehicleHalPropertyHandler { 541 542 private int mState = VehicleAudioFocusState.STATE_LOSS; 543 private int mStreams = 0; 544 private int mExtFocus = 0; 545 private int mRequest; 546 private int mRequestedStreams; 547 private int mRequestedExtFocus; 548 private int mRequestedAudioContexts; 549 private final MockedCarTestBase mCarTest; 550 551 private final Semaphore mSetWaitSemaphore = new Semaphore(0); 552 553 FocusPropertyHandler(MockedCarTestBase carTest) { 554 mCarTest = carTest; 555 } 556 557 void sendAudioFocusState(int state, int streams, int extFocus) { 558 synchronized (this) { 559 mState = state; 560 mStreams = streams; 561 mExtFocus = extFocus; 562 } 563 mCarTest.getMockedVehicleHal().injectEvent( 564 VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_FOCUS) 565 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 566 .addIntValue(state, streams, extFocus, 0) 567 .build()); 568 } 569 570 int[] waitForAudioFocusRequest(long timeoutMs) throws Exception { 571 if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 572 fail("timeout"); 573 } 574 synchronized (this) { 575 return new int[] { mRequest, mRequestedStreams, mRequestedExtFocus, 576 mRequestedAudioContexts }; 577 } 578 } 579 580 @Override 581 public void onPropertySet(VehiclePropValue value) { 582 assertEquals(VehicleProperty.AUDIO_FOCUS, value.prop); 583 ArrayList<Integer> v = value.value.int32Values; 584 synchronized (this) { 585 mRequest = v.get(VehicleAudioFocusIndex.FOCUS); 586 mRequestedStreams = v.get(VehicleAudioFocusIndex.STREAMS); 587 mRequestedExtFocus = v.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE); 588 mRequestedAudioContexts = v.get(VehicleAudioFocusIndex.AUDIO_CONTEXTS); 589 } 590 mSetWaitSemaphore.release(); 591 } 592 593 @Override 594 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 595 assertEquals(VehicleProperty.AUDIO_FOCUS, value.prop); 596 int state, streams, extFocus; 597 synchronized (this) { 598 state = mState; 599 streams = mStreams; 600 extFocus = mExtFocus; 601 } 602 return VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_FOCUS) 603 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 604 .addIntValue(state, streams, extFocus, 0) 605 .build(); 606 } 607 608 @Override 609 public void onPropertySubscribe(int property, int zones, float sampleRate) { 610 assertEquals(AUDIO_FOCUS, property); 611 } 612 613 @Override 614 public void onPropertyUnsubscribe(int property) { 615 assertEquals(AUDIO_FOCUS, property); 616 } 617 } 618} 619