1 /* 2 * Copyright (C) 2021 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 android.car.cts; 18 19 import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME; 20 import static android.car.media.CarAudioManager.AUDIO_FEATURE_AUDIO_MIRRORING; 21 import static android.car.media.CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING; 22 import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_EVENTS; 23 import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING; 24 import static android.car.media.CarAudioManager.AUDIO_MIRROR_CAN_ENABLE; 25 import static android.car.media.CarAudioManager.INVALID_AUDIO_ZONE; 26 import static android.car.media.CarAudioManager.INVALID_REQUEST_ID; 27 import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE; 28 import static android.car.test.mocks.JavaMockitoHelper.await; 29 import static android.media.AudioAttributes.USAGE_MEDIA; 30 31 import static com.google.common.truth.Truth.assertThat; 32 import static com.google.common.truth.Truth.assertWithMessage; 33 34 import static org.junit.Assert.assertThrows; 35 import static org.junit.Assume.assumeFalse; 36 import static org.junit.Assume.assumeTrue; 37 38 import android.app.UiAutomation; 39 import android.car.Car; 40 import android.car.CarOccupantZoneManager; 41 import android.car.CarOccupantZoneManager.OccupantZoneInfo; 42 import android.car.PlatformVersion; 43 import android.car.cts.utils.ProtoDumpUtils; 44 import android.car.feature.Flags; 45 import android.car.media.AudioZonesMirrorStatusCallback; 46 import android.car.media.CarAudioManager; 47 import android.car.media.CarAudioZoneConfigInfo; 48 import android.car.media.CarVolumeGroupInfo; 49 import android.car.media.MediaAudioRequestStatusCallback; 50 import android.car.media.PrimaryZoneMediaAudioRequestCallback; 51 import android.car.media.SwitchAudioZoneConfigCallback; 52 import android.car.test.PermissionsCheckerRule; 53 import android.car.test.PermissionsCheckerRule.EnsureHasPermission; 54 import android.car.test.util.CarAudioManagerTestUtils; 55 import android.media.AudioDeviceAttributes; 56 import android.media.AudioDeviceInfo; 57 import android.os.SystemClock; 58 import android.platform.test.annotations.AppModeFull; 59 import android.platform.test.annotations.RequiresFlagsDisabled; 60 import android.platform.test.annotations.RequiresFlagsEnabled; 61 import android.util.Log; 62 import android.util.SparseArray; 63 import android.view.KeyEvent; 64 65 import androidx.test.ext.junit.runners.AndroidJUnit4; 66 import androidx.test.platform.app.InstrumentationRegistry; 67 68 import com.android.car.audio.CarAudioDumpProto; 69 import com.android.car.audio.CarAudioDumpProto.CarAudioZoneConfigProto; 70 import com.android.car.audio.CarAudioDumpProto.CarAudioZoneProto; 71 import com.android.car.audio.CarAudioDumpProto.CarVolumeGroupProto; 72 import com.android.compatibility.common.util.ApiTest; 73 import com.android.compatibility.common.util.ShellUtils; 74 75 import org.junit.After; 76 import org.junit.Before; 77 import org.junit.Rule; 78 import org.junit.Test; 79 import org.junit.runner.RunWith; 80 81 import java.util.ArrayList; 82 import java.util.List; 83 import java.util.concurrent.CountDownLatch; 84 import java.util.concurrent.Executor; 85 import java.util.concurrent.Executors; 86 import java.util.regex.Matcher; 87 import java.util.regex.Pattern; 88 import java.util.stream.Collectors; 89 90 @RunWith(AndroidJUnit4.class) 91 @AppModeFull(reason = "Instant Apps cannot get car related permissions") 92 public final class CarAudioManagerTest extends AbstractCarTestCase { 93 94 private static final String TAG = CarAudioManagerTest.class.getSimpleName(); 95 96 private static final long WAIT_TIMEOUT_MS = 5_000; 97 98 private static final Pattern ZONE_PATTERN = Pattern.compile( 99 "CarAudioZone\\(.*:(\\d?)\\) isPrimary\\? (.*?)\n.*Current Config Id: (\\d?)"); 100 private static final Pattern VOLUME_GROUP_PATTERN = Pattern.compile( 101 "CarVolumeGroup\\((\\d?)\\)\n.*Name\\((.*?)\\)\n.*Zone Id\\((\\d?)\\)\n" 102 + ".*Configuration Id\\((\\d?)\\)"); 103 private static final Pattern ZONE_CONFIG_PATTERN = Pattern.compile( 104 "CarAudioZoneConfig\\((.*?):(\\d?)\\) of zone (\\d?) isDefault\\? (.*?)"); 105 private static final Pattern PRIMARY_ZONE_MEDIA_REQUEST_APPROVERS_PATTERN = 106 Pattern.compile("Media request callbacks\\[(\\d+)\\]:"); 107 108 private static final int USAGE_INVALID = -1; 109 private static final int VOLUME_FLAGS = 0; 110 private static final int INVALID_VOLUME_GROUP_ID = -1; 111 private static final int LEGACY_ZONE_ID = 0; 112 private static final int LEGACY_VOLUME_GROUP_ID = 0; 113 private static final int LEGACY_GROUP_VOLUME_COUNT = 3; 114 115 @Rule 116 public final PermissionsCheckerRule mPermissionsCheckerRule = new PermissionsCheckerRule(); 117 118 private static final UiAutomation UI_AUTOMATION = 119 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 120 121 private CarAudioManager mCarAudioManager; 122 private CarAudioManagerTestUtils.SyncCarVolumeCallback mCallback; 123 private int mZoneId = LEGACY_ZONE_ID; 124 private int mConfigId = -1; 125 private int mVolumeGroupId = -1; 126 private int mVolumeGroupCount = LEGACY_GROUP_VOLUME_COUNT; 127 private CarOccupantZoneManager mCarOccupantZoneManager; 128 private TestPrimaryZoneMediaAudioRequestStatusCallback mRequestCallback; 129 private long mMediaRequestId = INVALID_REQUEST_ID; 130 private String mCarAudioServiceDump; 131 private CarAudioDumpProto mCarAudioServiceProtoDump; 132 private TestAudioZonesMirrorStatusCallback mAudioZonesMirrorCallback; 133 private long mMirrorRequestId = INVALID_REQUEST_ID; 134 private CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback mEventCallback; 135 136 @Before setUp()137 public void setUp() throws Exception { 138 mCarAudioManager = getCar().getCarManager(CarAudioManager.class); 139 mCarOccupantZoneManager = getCar().getCarManager(CarOccupantZoneManager.class); 140 if (Flags.carDumpToProto()) { 141 mCarAudioServiceProtoDump = CarAudioDumpProto.parseFrom( 142 ProtoDumpUtils.executeProtoDumpShellCommand("CarAudioService")); 143 } else { 144 mCarAudioServiceDump = ShellUtils.runShellCommand( 145 "dumpsys car_service --services CarAudioService"); 146 } 147 } 148 149 @After cleanUp()150 public void cleanUp() { 151 if (mCallback != null) { 152 // Unregistering the last callback requires PERMISSION_CAR_CONTROL_AUDIO_VOLUME 153 runWithCarControlAudioVolumePermission( 154 () -> mCarAudioManager.unregisterCarVolumeCallback(mCallback)); 155 } 156 157 if (mMediaRequestId != INVALID_REQUEST_ID) { 158 Log.w(TAG, "Cancelling media request " + mMediaRequestId); 159 mCarAudioManager.cancelMediaAudioOnPrimaryZone(mMediaRequestId); 160 } 161 162 if (mRequestCallback != null) { 163 Log.w(TAG, "Releasing media request callback"); 164 mCarAudioManager.clearPrimaryZoneMediaAudioRequestCallback(); 165 } 166 167 if (mAudioZonesMirrorCallback != null) { 168 Log.i(TAG, "Releasing audio mirror request callback"); 169 mCarAudioManager.clearAudioZonesMirrorStatusCallback(); 170 } 171 172 if (mMirrorRequestId != INVALID_REQUEST_ID) { 173 Log.i(TAG, "Disabling audio mirror for request: " + mMirrorRequestId); 174 mCarAudioManager.disableAudioMirror(mMirrorRequestId); 175 } 176 177 if (mEventCallback != null && Car.getPlatformVersion().isAtLeast( 178 PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0)) { 179 runWithCarControlAudioVolumePermission( 180 () -> mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback)); 181 } 182 } 183 184 @Test 185 @ApiTest(apis = {"android.car.media.CarAudioManager#isAudioFeatureEnabled"}) isAudioFeatureEnabled_withVolumeGroupMuteFeature_succeeds()186 public void isAudioFeatureEnabled_withVolumeGroupMuteFeature_succeeds() { 187 boolean volumeGroupMutingEnabled = mCarAudioManager.isAudioFeatureEnabled( 188 AUDIO_FEATURE_VOLUME_GROUP_MUTING); 189 190 assertThat(volumeGroupMutingEnabled).isAnyOf(true, false); 191 } 192 193 @Test 194 @ApiTest(apis = {"android.car.media.CarAudioManager#isAudioFeatureEnabled"}) isAudioFeatureEnabled_withDynamicRoutingFeature_succeeds()195 public void isAudioFeatureEnabled_withDynamicRoutingFeature_succeeds() { 196 boolean dynamicRoutingEnabled = mCarAudioManager.isAudioFeatureEnabled( 197 AUDIO_FEATURE_DYNAMIC_ROUTING); 198 199 assertThat(dynamicRoutingEnabled).isAnyOf(true, false); 200 } 201 202 @Test 203 @ApiTest(apis = {"android.car.media.CarAudioManager#isAudioFeatureEnabled"}) isAudioFeatureEnabled_withVolumeGroupEventsFeature_succeeds()204 public void isAudioFeatureEnabled_withVolumeGroupEventsFeature_succeeds() { 205 boolean volumeGroupEventsEnabled = mCarAudioManager.isAudioFeatureEnabled( 206 AUDIO_FEATURE_VOLUME_GROUP_EVENTS); 207 208 assertWithMessage("Car volume group events feature").that(volumeGroupEventsEnabled) 209 .isAnyOf(true, false); 210 } 211 212 @Test 213 @ApiTest(apis = {"android.car.media.CarAudioManager#isAudioFeatureEnabled"}) isAudioFeatureEnabled_withNonAudioFeature_fails()214 public void isAudioFeatureEnabled_withNonAudioFeature_fails() { 215 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 216 () -> mCarAudioManager.isAudioFeatureEnabled(-1)); 217 218 assertThat(exception).hasMessageThat().contains("Unknown Audio Feature"); 219 } 220 221 @Test 222 @ApiTest(apis = {"android.car.media.CarAudioManager#isAudioFeatureEnabled(int)", 223 "android.car.media.CarAudioManager#AUDIO_FEATURE_AUDIO_MIRRORING"}) isAudioFeatureEnabled_withAudioMirrorFeature_succeeds()224 public void isAudioFeatureEnabled_withAudioMirrorFeature_succeeds() { 225 boolean audioMirroringEnabled = mCarAudioManager.isAudioFeatureEnabled( 226 AUDIO_FEATURE_AUDIO_MIRRORING); 227 228 assertThat(audioMirroringEnabled).isAnyOf(true, false); 229 } 230 231 @Test 232 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 233 @ApiTest(apis = {"android.car.media.CarAudioManager#canEnableAudioMirror"}) canEnableAudioMirror()234 public void canEnableAudioMirror() { 235 assumeAudioMirrorEnabled(); 236 237 int status = mCarAudioManager.canEnableAudioMirror(); 238 239 assertWithMessage("Can enable audio mirror status with feature supported") 240 .that(status).isEqualTo(AUDIO_MIRROR_CAN_ENABLE); 241 } 242 243 @Test 244 @ApiTest(apis = { 245 "android.car.media.CarAudioManager#registerCarVolumeCallback"}) registerCarVolumeCallback_nullCallback_throwsNPE()246 public void registerCarVolumeCallback_nullCallback_throwsNPE() { 247 assertThrows(NullPointerException.class, 248 () -> mCarAudioManager.registerCarVolumeCallback(null)); 249 } 250 251 @Test 252 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 253 @ApiTest(apis = { 254 "android.car.media.CarAudioManager#registerCarVolumeCallback"}) registerCarVolumeCallback_onGroupVolumeChanged()255 public void registerCarVolumeCallback_onGroupVolumeChanged() throws Exception { 256 assumeDynamicRoutingIsEnabled(); 257 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 258 259 mCarAudioManager.registerCarVolumeCallback(mCallback); 260 261 injectVolumeDownKeyEvent(); 262 assertWithMessage("CarVolumeCallback#onGroupVolumeChanged should be called") 263 .that(mCallback.receivedGroupVolumeChanged()) 264 .isTrue(); 265 } 266 267 @Test 268 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 269 @ApiTest(apis = { 270 "android.car.media.CarAudioManager#registerCarVolumeCallback"}) registerCarVolumeCallback_onMasterMuteChanged()271 public void registerCarVolumeCallback_onMasterMuteChanged() throws Exception { 272 assumeDynamicRoutingIsEnabled(); 273 assumeVolumeGroupMutingIsDisabled(); 274 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 275 276 mCarAudioManager.registerCarVolumeCallback(mCallback); 277 278 injectVolumeMuteKeyEvent(); 279 try { 280 assertWithMessage("CarVolumeCallback#onMasterMuteChanged should be called") 281 .that(mCallback.receivedMasterMuteChanged()) 282 .isTrue(); 283 } finally { 284 injectVolumeMuteKeyEvent(); 285 } 286 } 287 288 @Test 289 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 290 @ApiTest(apis = { 291 "android.car.media.CarAudioManager#registerCarVolumeCallback"}) registerCarVolumeCallback_onGroupMuteChanged()292 public void registerCarVolumeCallback_onGroupMuteChanged() throws Exception { 293 assumeDynamicRoutingIsEnabled(); 294 assumeVolumeGroupMutingIsEnabled(); 295 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 296 297 readFirstZoneAndVolumeGroup(); 298 mCarAudioManager.registerCarVolumeCallback(mCallback); 299 setVolumeGroupMute(mZoneId, mVolumeGroupId, /* mute= */ true); 300 setVolumeGroupMute(mZoneId, mVolumeGroupId, /* mute= */ false); 301 302 assertWithMessage("CarVolumeCallback#onGroupMuteChanged should be called") 303 .that(mCallback.receivedGroupMuteChanged()).isTrue(); 304 assertWithMessage("CarVolumeCallback#onGroupMuteChanged wrong zoneId") 305 .that(mCallback.zoneId).isEqualTo(mZoneId); 306 assertWithMessage("CarVolumeCallback#onGroupMuteChanged wrong groupId") 307 .that(mCallback.groupId).isEqualTo(mVolumeGroupId); 308 } 309 310 @Test 311 @ApiTest(apis = { 312 "android.car.media.CarAudioManager#unregisterCarVolumeCallback"}) unregisterCarVolumeCallback_nullCallback_throws()313 public void unregisterCarVolumeCallback_nullCallback_throws() { 314 assertThrows(NullPointerException.class, 315 () -> mCarAudioManager.unregisterCarVolumeCallback(null)); 316 } 317 318 @Test 319 @ApiTest(apis = { 320 "android.car.media.CarAudioManager#unregisterCarVolumeCallback"}) unregisterCarVolumeCallback_unregisteredCallback_doesNotReceiveCallback()321 public void unregisterCarVolumeCallback_unregisteredCallback_doesNotReceiveCallback() 322 throws Exception { 323 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 324 325 mCarAudioManager.unregisterCarVolumeCallback(mCallback); 326 327 assertWithMessage("CarVolumeCallback#onGroupVolumeChanged should not be called") 328 .that(mCallback.receivedGroupVolumeChanged()) 329 .isFalse(); 330 } 331 332 @Test 333 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 334 @ApiTest(apis = { 335 "android.car.media.CarAudioManager#unregisterCarVolumeCallback"}) unregisterCarVolumeCallback_noLongerReceivesCallback()336 public void unregisterCarVolumeCallback_noLongerReceivesCallback() throws Exception { 337 assumeDynamicRoutingIsEnabled(); 338 CarAudioManagerTestUtils.SyncCarVolumeCallback callback = 339 new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 340 mCarAudioManager.registerCarVolumeCallback(callback); 341 mCarAudioManager.unregisterCarVolumeCallback(callback); 342 343 injectVolumeDownKeyEvent(); 344 345 assertWithMessage("CarVolumeCallback#onGroupVolumeChanged should not be called") 346 .that(callback.receivedGroupVolumeChanged()) 347 .isFalse(); 348 } 349 350 @Test 351 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 352 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupInfo"}) 353 @RequiresFlagsDisabled(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME) getVolumeGroupInfo_withMinMaxActivationVolumeFlagDisabled()354 public void getVolumeGroupInfo_withMinMaxActivationVolumeFlagDisabled() { 355 assumeDynamicRoutingIsEnabled(); 356 int groupCount = mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); 357 358 for (int index = 0; index < groupCount; index++) { 359 int minIndex = mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, index); 360 int maxIndex = mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, index); 361 CarVolumeGroupInfo info = 362 mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index); 363 expectWithMessage("Car volume group id for info %s and group %s", info, index) 364 .that(info.getId()).isEqualTo(index); 365 expectWithMessage("Car volume group info zone for info %s and group %s", 366 info, index).that(info.getZoneId()).isEqualTo(PRIMARY_AUDIO_ZONE); 367 expectWithMessage("Car volume group info max index for info %s and group %s", 368 info, index).that(info.getMaxVolumeGainIndex()).isEqualTo(maxIndex); 369 expectWithMessage("Car volume group info min index for info %s and group %s", 370 info, index).that(info.getMinVolumeGainIndex()).isEqualTo(minIndex); 371 } 372 } 373 374 @Test 375 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 376 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupInfo", 377 "android.car.media.CarVolumeGroupInfo#getMaxActivationVolumeGainIndex", 378 "android.car.media.CarVolumeGroupInfo#getMinActivationVolumeGainIndex"}) 379 @RequiresFlagsEnabled(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME) getVolumeGroupInfo_withMinMaxActivationVolumeFlagEnabled()380 public void getVolumeGroupInfo_withMinMaxActivationVolumeFlagEnabled() { 381 assumeDynamicRoutingIsEnabled(); 382 int groupCount = mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); 383 384 for (int index = 0; index < groupCount; index++) { 385 int minIndex = mCarAudioManager.getGroupMinVolume(PRIMARY_AUDIO_ZONE, index); 386 int maxIndex = mCarAudioManager.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, index); 387 CarVolumeGroupInfo info = 388 mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index); 389 int minActivationIndex = info.getMinActivationVolumeGainIndex(); 390 int maxActivationIndex = info.getMaxActivationVolumeGainIndex(); 391 392 expectWithMessage("Car volume group id for info %s and group %s", info, index) 393 .that(info.getId()).isEqualTo(index); 394 expectWithMessage("Car volume group info zone for info %s and group %s", 395 info, index).that(info.getZoneId()).isEqualTo(PRIMARY_AUDIO_ZONE); 396 expectWithMessage("Car volume group info max index for info %s and group %s", 397 info, index).that(info.getMaxVolumeGainIndex()).isEqualTo(maxIndex); 398 expectWithMessage("Car volume group info min index for info %s and group %s", 399 info, index).that(info.getMinVolumeGainIndex()).isEqualTo(minIndex); 400 expectWithMessage("Car volume group info min activation volume for info %s and" 401 + " group %s", info, index).that(minActivationIndex).isAtLeast(minIndex); 402 expectWithMessage("Car volume group info max activation volume for info %s and" 403 + " group %s", info, index).that(maxActivationIndex).isAtMost(maxIndex); 404 expectWithMessage("Max activation volume and min activation volume for info %s" 405 + " and group %s", info, index).that(maxActivationIndex) 406 .isGreaterThan(minActivationIndex); 407 } 408 } 409 410 @Test 411 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 412 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupInfosForZone"}) getVolumeGroupInfosForZone()413 public void getVolumeGroupInfosForZone() { 414 assumeDynamicRoutingIsEnabled(); 415 int groupCount = mCarAudioManager.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); 416 417 List<CarVolumeGroupInfo> infos = 418 mCarAudioManager.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE); 419 420 expectWithMessage("Car volume group infos for primary zone") 421 .that(infos).hasSize(groupCount); 422 for (int index = 0; index < groupCount; index++) { 423 CarVolumeGroupInfo info = 424 mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index); 425 expectWithMessage("Car volume group infos for info %s and group %s", info, index) 426 .that(infos).contains(info); 427 } 428 } 429 430 @Test 431 @EnsureHasPermission({Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME, 432 Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS}) 433 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupInfosForZone", 434 "android.car.media.CarVolumeGroupInfo#getAudioDeviceAttributes", 435 "android.car.media.CarVolumeGroupInfo#isDefault"}) 436 @RequiresFlagsEnabled(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES) getVolumeGroupInfosForZone_forPrimaryZone_withAudioDeviceAttributes()437 public void getVolumeGroupInfosForZone_forPrimaryZone_withAudioDeviceAttributes() 438 throws Exception { 439 assumeDynamicRoutingIsEnabled(); 440 setUpDefaultCarAudioConfigurationForZone(PRIMARY_AUDIO_ZONE); 441 442 List<CarVolumeGroupInfo> infos = 443 mCarAudioManager.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE); 444 445 expectWithMessage("Primary zone's car volume groups").that(infos).isNotEmpty(); 446 for (int count = 0; count < infos.size(); count++) { 447 CarVolumeGroupInfo info = infos.get(count); 448 List<Integer> types = info.getAudioDeviceAttributes().stream() 449 .map(AudioDeviceAttributes::getType).collect(Collectors.toList()); 450 expectWithMessage("Primary zone's car volume group %s types", info.getId()) 451 .that(types).isNotEmpty(); 452 for (int index = 0; index < types.size(); index++) { 453 expectWithMessage("Primary zone's car volume group device type " 454 + " for group %s device index %s", info.getId(), index) 455 .that(types.get(index)).isEqualTo(AudioDeviceInfo.TYPE_BUS); 456 } 457 } 458 } 459 460 @Test 461 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 462 @ApiTest(apis = {"android.car.media.CarAudioManager" 463 + "#getAudioAttributesForVolumeGroup"}) getAudioAttributesForVolumeGroup()464 public void getAudioAttributesForVolumeGroup() { 465 assumeDynamicRoutingIsEnabled(); 466 CarVolumeGroupInfo info = 467 mCarAudioManager.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, /* groupId= */ 0); 468 469 expectWithMessage("Car volume audio attributes") 470 .that(mCarAudioManager.getAudioAttributesForVolumeGroup(info)) 471 .isNotEmpty(); 472 } 473 474 @Test 475 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 476 @ApiTest(apis = {"android.car.media.CarAudioManager#getGroupMaxVolume", 477 "android.car.media.CarAudioManager#getGroupMinVolume", 478 "android.car.media.CarAudioManager#getGroupVolume"}) getGroupVolume()479 public void getGroupVolume() { 480 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 481 assumePrimaryZone(); 482 } 483 int maxIndex = mCarAudioManager.getGroupMaxVolume(mVolumeGroupId); 484 int minIndex = mCarAudioManager.getGroupMinVolume(mVolumeGroupId); 485 486 int currentIndex = mCarAudioManager.getGroupVolume(mVolumeGroupId); 487 488 assertWithMessage("Current maximum volume for primary zone") 489 .that(currentIndex).isAtMost(maxIndex); 490 assertWithMessage("Current minimum volume for primary zone") 491 .that(currentIndex).isAtLeast(minIndex); 492 } 493 494 @Test 495 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 496 @ApiTest(apis = {"android.car.media.CarAudioManager#getGroupMaxVolume", 497 "android.car.media.CarAudioManager#getGroupMinVolume", 498 "android.car.media.CarAudioManager#getGroupVolume"}) getGroupVolume_withZoneId()499 public void getGroupVolume_withZoneId() { 500 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 501 readFirstZoneAndVolumeGroup(); 502 } 503 int maxIndex = mCarAudioManager.getGroupMaxVolume(mZoneId, mVolumeGroupId); 504 int minIndex = mCarAudioManager.getGroupMinVolume(mZoneId, mVolumeGroupId); 505 506 int currentIndex = mCarAudioManager.getGroupVolume(mZoneId, mVolumeGroupId); 507 508 assertWithMessage("Current maximum volume for zone %s volume group %s", mZoneId, 509 mVolumeGroupId).that(currentIndex).isAtMost(maxIndex); 510 assertWithMessage("Current minimum volume for zone %s volume group %s", mZoneId, 511 mVolumeGroupId).that(currentIndex).isAtLeast(minIndex); 512 } 513 514 @Test 515 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 516 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_toMax_succeeds()517 public void setGroupVolume_toMax_succeeds() { 518 assumeDynamicRoutingIsEnabled(); 519 assumePrimaryZone(); 520 int prevIndex = mCarAudioManager.getGroupVolume(mZoneId, mVolumeGroupId); 521 int maxIndex = mCarAudioManager.getGroupMaxVolume(mVolumeGroupId); 522 523 mCarAudioManager.setGroupVolume(mVolumeGroupId, maxIndex, VOLUME_FLAGS); 524 525 try { 526 assertWithMessage("Current volume after setting to max for primary zone volume group" 527 + " %s", mVolumeGroupId).that(mCarAudioManager.getGroupVolume(mVolumeGroupId)) 528 .isEqualTo(maxIndex); 529 } finally { 530 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, prevIndex, VOLUME_FLAGS); 531 } 532 } 533 534 @Test 535 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 536 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_toMin_succeeds()537 public void setGroupVolume_toMin_succeeds() { 538 assumeDynamicRoutingIsEnabled(); 539 assumePrimaryZone(); 540 int prevIndex = mCarAudioManager.getGroupVolume(mZoneId, mVolumeGroupId); 541 int minIndex = mCarAudioManager.getGroupMinVolume(mVolumeGroupId); 542 543 mCarAudioManager.setGroupVolume(mVolumeGroupId, minIndex, VOLUME_FLAGS); 544 545 try { 546 assertWithMessage("Current volume after setting to min for primary zone volume group" 547 + " %s", mVolumeGroupId).that(mCarAudioManager.getGroupVolume(mVolumeGroupId)) 548 .isEqualTo(minIndex); 549 } finally { 550 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, prevIndex, VOLUME_FLAGS); 551 } 552 } 553 554 @Test 555 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 556 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_withZone_toMax_succeeds()557 public void setGroupVolume_withZone_toMax_succeeds() { 558 assumeDynamicRoutingIsEnabled(); 559 readFirstZoneAndVolumeGroup(); 560 int prevIndex = mCarAudioManager.getGroupVolume(mZoneId, mVolumeGroupId); 561 int maxIndex = mCarAudioManager.getGroupMaxVolume(mZoneId, mVolumeGroupId); 562 563 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, maxIndex, VOLUME_FLAGS); 564 565 try { 566 assertWithMessage("Current volume after setting to max for zone %s volume group %s", 567 mZoneId, mVolumeGroupId).that(mCarAudioManager.getGroupVolume(mZoneId, 568 mVolumeGroupId)).isEqualTo(maxIndex); 569 } finally { 570 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, prevIndex, VOLUME_FLAGS); 571 } 572 } 573 574 @Test 575 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 576 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_withZone_toMin_succeeds()577 public void setGroupVolume_withZone_toMin_succeeds() { 578 assumeDynamicRoutingIsEnabled(); 579 readFirstZoneAndVolumeGroup(); 580 int prevIndex = mCarAudioManager.getGroupVolume(mZoneId, mVolumeGroupId); 581 int minIndex = mCarAudioManager.getGroupMinVolume(mZoneId, mVolumeGroupId); 582 583 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, minIndex, VOLUME_FLAGS); 584 585 try { 586 assertWithMessage("Current volume after setting to min for zone %s volume group %s", 587 mZoneId, mVolumeGroupId).that(mCarAudioManager.getGroupVolume(mZoneId, 588 mVolumeGroupId)).isEqualTo(minIndex); 589 } finally { 590 mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, prevIndex, VOLUME_FLAGS); 591 } 592 } 593 594 @Test 595 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 596 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_aboveMax_throwsException()597 public void setGroupVolume_aboveMax_throwsException() { 598 assumeDynamicRoutingIsEnabled(); 599 readFirstZoneAndVolumeGroup(); 600 int maxIndex = mCarAudioManager.getGroupMaxVolume(mZoneId, mVolumeGroupId); 601 602 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 603 () -> mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, maxIndex + 1, 604 VOLUME_FLAGS)); 605 606 assertWithMessage("Exception for setting volume above max") 607 .that(exception).hasMessageThat().contains("Gain out of range"); 608 } 609 610 @Test 611 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 612 @ApiTest(apis = {"android.car.media.CarAudioManager#setGroupVolume"}) setGroupVolume_belowMin_throwsException()613 public void setGroupVolume_belowMin_throwsException() { 614 assumeDynamicRoutingIsEnabled(); 615 readFirstZoneAndVolumeGroup(); 616 int minIndex = mCarAudioManager.getGroupMinVolume(mZoneId, mVolumeGroupId); 617 618 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 619 () -> mCarAudioManager.setGroupVolume(mZoneId, mVolumeGroupId, minIndex - 1, 620 VOLUME_FLAGS)); 621 622 assertWithMessage("Exception for setting volume below min") 623 .that(exception).hasMessageThat().contains("Gain out of range"); 624 } 625 626 @Test 627 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 628 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupCount"}) getVolumeGroupCount()629 public void getVolumeGroupCount() { 630 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 631 assumePrimaryZone(); 632 } 633 634 assertWithMessage("Primary zone volume group count") 635 .that(mCarAudioManager.getVolumeGroupCount()).isEqualTo(mVolumeGroupCount); 636 } 637 638 @Test 639 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 640 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupCount"}) getVolumeGroupCount_withZoneIdAndDynamicRouting()641 public void getVolumeGroupCount_withZoneIdAndDynamicRouting() { 642 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 643 readFirstZoneAndVolumeGroup(); 644 } 645 646 assertWithMessage("Zone %s volume group count", mZoneId) 647 .that(mCarAudioManager.getVolumeGroupCount(mZoneId)).isEqualTo(mVolumeGroupCount); 648 } 649 650 @Test 651 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 652 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupCount"}) getVolumeGroupCount_withInvalidZoneId_throwsException()653 public void getVolumeGroupCount_withInvalidZoneId_throwsException() { 654 assumeDynamicRoutingIsEnabled(); 655 assumePrimaryZone(); 656 657 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 658 () -> mCarAudioManager.getVolumeGroupCount(INVALID_AUDIO_ZONE)); 659 660 assertWithMessage("Invalid zone volume group count exception").that(exception) 661 .hasMessageThat().contains("Invalid audio zone Id"); 662 } 663 664 @Test 665 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 666 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupIdForUsage"}) getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidId()667 public void getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidId() { 668 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 669 assumePrimaryZone(); 670 } 671 672 int volumeGroupId = mCarAudioManager.getVolumeGroupIdForUsage(USAGE_INVALID); 673 674 assertWithMessage("Volume group id for invalid usage").that(volumeGroupId) 675 .isEqualTo(INVALID_VOLUME_GROUP_ID); 676 } 677 678 @Test 679 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 680 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupIdForUsage"}) getVolumeGroupIdForUsage_withInvalidZoneId_throwsException()681 public void getVolumeGroupIdForUsage_withInvalidZoneId_throwsException() { 682 assumeDynamicRoutingIsEnabled(); 683 684 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 685 () -> mCarAudioManager.getVolumeGroupIdForUsage(INVALID_AUDIO_ZONE, USAGE_MEDIA)); 686 687 assertWithMessage("Invalid zone volume group for media usage exception").that(exception) 688 .hasMessageThat().contains("Invalid audio zone Id"); 689 } 690 691 @Test 692 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 693 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupIdForUsage"}) getVolumeGroupIdForUsage_returnsValidId()694 public void getVolumeGroupIdForUsage_returnsValidId() { 695 if (mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) { 696 assumePrimaryZone(); 697 } 698 699 int volumeGroupId = mCarAudioManager.getVolumeGroupIdForUsage(USAGE_MEDIA); 700 701 assertWithMessage("Valid volume group id in primary zone") 702 .that(volumeGroupId).isNotEqualTo(INVALID_VOLUME_GROUP_ID); 703 } 704 705 @Test 706 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 707 @ApiTest(apis = {"android.car.media.CarAudioManager#getVolumeGroupIdForUsage"}) getVolumeGroupIdForUsage_withZoneId_returnsValidId()708 public void getVolumeGroupIdForUsage_withZoneId_returnsValidId() { 709 assumeDynamicRoutingIsEnabled(); 710 readFirstZoneAndVolumeGroup(); 711 712 int volumeGroupId = mCarAudioManager.getVolumeGroupIdForUsage(mZoneId, USAGE_MEDIA); 713 714 assertWithMessage("Valid volume group id for media usage in zone %s", mZoneId) 715 .that(volumeGroupId).isNotEqualTo(INVALID_VOLUME_GROUP_ID); 716 } 717 718 @Test 719 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 720 @ApiTest(apis = {"android.car.media.CarAudioManager#getUsagesForVolumeGroupId"}) getUsagesForVolumeGroupId_returnsAtLeastOneUsage()721 public void getUsagesForVolumeGroupId_returnsAtLeastOneUsage() { 722 assumeDynamicRoutingIsEnabled(); 723 assumePrimaryZone(); 724 725 int[] usages = mCarAudioManager.getUsagesForVolumeGroupId(mVolumeGroupId); 726 727 assertVolumeGroupIdForUsages(PRIMARY_AUDIO_ZONE, mVolumeGroupId, usages, 728 "with dynamic routing"); 729 } 730 731 @Test 732 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 733 @ApiTest(apis = {"android.car.media.CarAudioManager#getUsagesForVolumeGroupId"}) getUsagesForVolumeGroupId_withoutDynamicRouting_returnsAtLeastOneUsage()734 public void getUsagesForVolumeGroupId_withoutDynamicRouting_returnsAtLeastOneUsage() { 735 assumeDynamicRoutingIsDisabled(); 736 737 int[] usages = mCarAudioManager.getUsagesForVolumeGroupId(LEGACY_VOLUME_GROUP_ID); 738 739 assertVolumeGroupIdForUsages(PRIMARY_AUDIO_ZONE, LEGACY_VOLUME_GROUP_ID, 740 usages, "with dynamic routing disabled"); 741 } 742 743 @Test 744 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 745 @ApiTest(apis = {"android.car.media.CarAudioManager#getUsagesForVolumeGroupId"}) getUsagesForVolumeGroupId_withZoneId_returnsAtLeastOneUsage()746 public void getUsagesForVolumeGroupId_withZoneId_returnsAtLeastOneUsage() { 747 assumeDynamicRoutingIsEnabled(); 748 readFirstZoneAndVolumeGroup(); 749 750 int[] usages = mCarAudioManager.getUsagesForVolumeGroupId(mVolumeGroupId); 751 752 assertVolumeGroupIdForUsages(mZoneId, mVolumeGroupId, usages, 753 "with id and dynamic routing"); 754 } 755 756 @Test 757 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 758 @ApiTest(apis = {"android.car.media.CarAudioManager#getUsagesForVolumeGroupId"}) getUsagesForVolumeGroupId_withZoneIdWithoutDynamicRouting_returnsAtLeastOneUsage()759 public void getUsagesForVolumeGroupId_withZoneIdWithoutDynamicRouting_returnsAtLeastOneUsage() { 760 assumeDynamicRoutingIsDisabled(); 761 762 int[] usages = mCarAudioManager.getUsagesForVolumeGroupId(LEGACY_VOLUME_GROUP_ID); 763 764 assertVolumeGroupIdForUsages(LEGACY_ZONE_ID, LEGACY_VOLUME_GROUP_ID, usages, 765 "with id and with dynamic routing disabled"); 766 } 767 768 @Test 769 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 770 @ApiTest(apis = {"android.car.media.CarAudioManager#getUsagesForVolumeGroupId"}) getUsagesForVolumeGroupId_withInvalidZone_throwsException()771 public void getUsagesForVolumeGroupId_withInvalidZone_throwsException() { 772 assumeDynamicRoutingIsEnabled(); 773 assumePrimaryZone(); 774 775 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 776 () -> mCarAudioManager.getUsagesForVolumeGroupId(INVALID_AUDIO_ZONE, 777 mVolumeGroupId)); 778 779 assertWithMessage("Exception for getting usage for volume group in invalid zone") 780 .that(exception).hasMessageThat().contains("Invalid audio zone Id"); 781 } 782 783 @Test 784 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 785 @ApiTest(apis = {"android.car.media.CarAudioManager#getOutputDeviceForUsage"}) getOutputDeviceForUsage_withoutDynamicRouting_throws()786 public void getOutputDeviceForUsage_withoutDynamicRouting_throws() { 787 assumeDynamicRoutingIsDisabled(); 788 789 IllegalStateException exception = assertThrows(IllegalStateException.class, 790 () -> mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA)); 791 792 assertWithMessage("Exception for getting media output device with dynamic routing disabled") 793 .that(exception).hasMessageThat().contains("Non legacy routing"); 794 } 795 796 @Test 797 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 798 @ApiTest(apis = {"android.car.media.CarAudioManager#getOutputDeviceForUsage"}) getOutputDeviceForUsage_withInvalidZoneId_throws()799 public void getOutputDeviceForUsage_withInvalidZoneId_throws() { 800 assumeDynamicRoutingIsEnabled(); 801 802 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 803 () -> mCarAudioManager.getOutputDeviceForUsage(INVALID_AUDIO_ZONE, USAGE_MEDIA)); 804 805 assertWithMessage("Exception for getting invalid zone media output device") 806 .that(exception).hasMessageThat().contains("Invalid audio zone Id"); 807 } 808 809 @Test 810 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 811 @ApiTest(apis = {"android.car.media.CarAudioManager#getOutputDeviceForUsage"}) getOutputDeviceForUsage_withInvalidUsage_throws()812 public void getOutputDeviceForUsage_withInvalidUsage_throws() { 813 assumeDynamicRoutingIsEnabled(); 814 815 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 816 () -> mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, USAGE_INVALID)); 817 818 assertWithMessage("Invalid usage output device exception") 819 .that(exception).hasMessageThat().contains("Invalid audio attribute"); 820 } 821 822 @Test 823 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 824 @ApiTest(apis = {"android.car.media.CarAudioManager#getOutputDeviceForUsage"}) getOutputDeviceForUsage_succeeds()825 public void getOutputDeviceForUsage_succeeds() { 826 assumeDynamicRoutingIsEnabled(); 827 828 AudioDeviceInfo deviceInfo = mCarAudioManager.getOutputDeviceForUsage(PRIMARY_AUDIO_ZONE, 829 USAGE_MEDIA); 830 831 assertWithMessage("Device for media in primary zone") 832 .that(deviceInfo).isNotNull(); 833 assertWithMessage("Sink device for media in primary zone") 834 .that(deviceInfo.isSink()).isTrue(); 835 } 836 837 @Test 838 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 839 @ApiTest(apis = {"android.car.media.CarAudioManager#getInputDevicesForZoneId"}) getInputDevicesForZoneId_withoutDynamicRouting_throws()840 public void getInputDevicesForZoneId_withoutDynamicRouting_throws() { 841 assumeDynamicRoutingIsDisabled(); 842 843 IllegalStateException exception = assertThrows(IllegalStateException.class, 844 () -> mCarAudioManager.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE)); 845 846 assertWithMessage("Exception for getting input devices with dynamic routing disabled") 847 .that(exception).hasMessageThat().contains("Non legacy routing"); 848 } 849 850 @Test 851 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 852 @ApiTest(apis = {"android.car.media.CarAudioManager#getInputDevicesForZoneId"}) getInputDevicesForZoneId_withInvalidZoneId_throws()853 public void getInputDevicesForZoneId_withInvalidZoneId_throws() { 854 assumeDynamicRoutingIsEnabled(); 855 856 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 857 () -> mCarAudioManager.getInputDevicesForZoneId(INVALID_AUDIO_ZONE)); 858 859 assertWithMessage("Exception for getting input devices with invalid volume group id") 860 .that(exception).hasMessageThat().contains("Invalid audio zone Id"); 861 } 862 863 @Test 864 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 865 @ApiTest(apis = {"android.car.media.CarAudioManager#getInputDevicesForZoneId"}) getInputDevicesForZoneId_succeeds()866 public void getInputDevicesForZoneId_succeeds() { 867 assumeDynamicRoutingIsEnabled(); 868 869 List<AudioDeviceInfo> audioDeviceInfos = mCarAudioManager.getInputDevicesForZoneId( 870 PRIMARY_AUDIO_ZONE); 871 872 assertWithMessage("Input devices for primary zone") 873 .that(audioDeviceInfos).isNotNull(); 874 for (int i = 0; i < audioDeviceInfos.size(); i++) { 875 assertWithMessage("Source device %s in primary zone", audioDeviceInfos.get(i) 876 .getAddress()).that(audioDeviceInfos.get(i).isSource()).isTrue(); 877 } 878 } 879 880 @Test 881 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 882 @ApiTest(apis = {"android.car.media.CarAudioManager" 883 + "#isMediaAudioAllowedInPrimaryZone"}) isMediaAudioAllowedInPrimaryZone_byDefault()884 public void isMediaAudioAllowedInPrimaryZone_byDefault() { 885 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 886 OccupantZoneInfo info = 887 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 888 889 assertWithMessage("Default media allowed status") 890 .that(mCarAudioManager.isMediaAudioAllowedInPrimaryZone(info)).isFalse(); 891 } 892 893 @Test 894 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 895 @ApiTest(apis = {"android.car.media.CarAudioManager" 896 + "#isMediaAudioAllowedInPrimaryZone"}) isMediaAudioAllowedInPrimaryZone_afterAllowed()897 public void isMediaAudioAllowedInPrimaryZone_afterAllowed() throws Exception { 898 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 899 setupMediaAudioRequestCallback(); 900 OccupantZoneInfo info = 901 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 902 requestToPlayMediaInPrimaryZone(info); 903 mRequestCallback.receivedMediaRequest(); 904 mCarAudioManager.allowMediaAudioOnPrimaryZone(mMediaRequestId, /* allow= */ true); 905 906 boolean approved = mCarAudioManager.isMediaAudioAllowedInPrimaryZone(info); 907 908 assertWithMessage("Approved media allowed status") 909 .that(approved).isTrue(); 910 } 911 912 @Test 913 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 914 @ApiTest(apis = {"android.car.media.CarAudioManager" 915 + "#isMediaAudioAllowedInPrimaryZone"}) isMediaAudioAllowedInPrimaryZone_afterRejected()916 public void isMediaAudioAllowedInPrimaryZone_afterRejected() throws Exception { 917 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 918 setupMediaAudioRequestCallback(); 919 OccupantZoneInfo info = 920 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 921 requestToPlayMediaInPrimaryZone(info); 922 mRequestCallback.receivedMediaRequest(); 923 mCarAudioManager.allowMediaAudioOnPrimaryZone(mMediaRequestId, /* allow= */ false); 924 925 boolean approved = mCarAudioManager.isMediaAudioAllowedInPrimaryZone(info); 926 927 assertWithMessage("Unapproved media allowed status") 928 .that(approved).isFalse(); 929 } 930 931 @Test 932 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 933 @ApiTest(apis = {"android.car.media.CarAudioManager" 934 + "#setPrimaryZoneMediaAudioRequestCallback"}) setPrimaryZoneMediaAudioRequestCallback()935 public void setPrimaryZoneMediaAudioRequestCallback() { 936 assumePassengerWithValidAudioZone(); 937 Executor executor = Executors.newFixedThreadPool(1); 938 TestPrimaryZoneMediaAudioRequestStatusCallback 939 requestCallback = new TestPrimaryZoneMediaAudioRequestStatusCallback(); 940 941 boolean registered = 942 mCarAudioManager.setPrimaryZoneMediaAudioRequestCallback(executor, requestCallback); 943 944 assertWithMessage("Set status of media request callback") 945 .that(registered).isTrue(); 946 } 947 948 @Test 949 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 950 @ApiTest(apis = {"android.car.media.CarAudioManager" 951 + "#requestMediaAudioOnPrimaryZone"}) requestMediaAudioOnPrimaryZone()952 public void requestMediaAudioOnPrimaryZone() throws Exception { 953 assumeDynamicRoutingIsEnabled(); 954 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 955 setupMediaAudioRequestCallback(); 956 OccupantZoneInfo info = 957 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 958 Executor callbackExecutor = Executors.newFixedThreadPool(1); 959 TestMediaAudioRequestStatusCallback callback = new TestMediaAudioRequestStatusCallback(); 960 961 mMediaRequestId = 962 mCarAudioManager.requestMediaAudioOnPrimaryZone(info, callbackExecutor, callback); 963 964 mRequestCallback.receivedMediaRequest(); 965 assertWithMessage("Received request id").that(mRequestCallback.mRequestId) 966 .isEqualTo(mMediaRequestId); 967 assertWithMessage("Received occupant info").that(mRequestCallback.mOccupantZoneInfo) 968 .isEqualTo(info); 969 } 970 971 @Test 972 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 973 @ApiTest(apis = {"android.car.media.CarAudioManager" 974 + "#requestMediaAudioOnPrimaryZone"}) requestMediaAudioOnPrimaryZone_withoutApprover()975 public void requestMediaAudioOnPrimaryZone_withoutApprover() throws Exception { 976 assumeDynamicRoutingIsEnabled(); 977 assumeNoPrimaryZoneAudioMediaApprovers(); 978 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 979 OccupantZoneInfo info = 980 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 981 Executor callbackExecutor = Executors.newFixedThreadPool(1); 982 TestMediaAudioRequestStatusCallback callback = new TestMediaAudioRequestStatusCallback(); 983 984 mMediaRequestId = 985 mCarAudioManager.requestMediaAudioOnPrimaryZone(info, callbackExecutor, callback); 986 987 callback.receivedApproval(); 988 assertWithMessage("Request id for rejected request") 989 .that(callback.mRequestId).isEqualTo(mMediaRequestId); 990 assertWithMessage("Rejected request status").that(callback.mStatus) 991 .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED); 992 } 993 994 @Test 995 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 996 @ApiTest(apis = {"android.car.media.CarAudioManager" 997 + "#allowMediaAudioOnPrimaryZone"}) allowMediaAudioOnPrimaryZone()998 public void allowMediaAudioOnPrimaryZone() throws Exception { 999 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 1000 setupMediaAudioRequestCallback(); 1001 OccupantZoneInfo info = 1002 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 1003 TestMediaAudioRequestStatusCallback callback = 1004 requestToPlayMediaInPrimaryZone(info); 1005 mRequestCallback.receivedMediaRequest(); 1006 1007 boolean succeeded = mCarAudioManager.allowMediaAudioOnPrimaryZone(mMediaRequestId, 1008 /* allow= */ true); 1009 1010 callback.receivedApproval(); 1011 assertWithMessage("Approved results for request in primary zone") 1012 .that(succeeded).isTrue(); 1013 assertWithMessage("Approved request id in primary zone") 1014 .that(callback.mRequestId).isEqualTo(mMediaRequestId); 1015 assertWithMessage("Approved request occupant in primary zone") 1016 .that(callback.mOccupantZoneInfo).isEqualTo(info); 1017 assertWithMessage("Audio status in primary zone").that(callback.mStatus) 1018 .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); 1019 } 1020 1021 @Test 1022 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1023 @ApiTest(apis = {"android.car.media.CarAudioManager" 1024 + "#allowMediaAudioOnPrimaryZone"}) allowMediaAudioOnPrimaryZone_withReject()1025 public void allowMediaAudioOnPrimaryZone_withReject() throws Exception { 1026 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 1027 setupMediaAudioRequestCallback(); 1028 OccupantZoneInfo info = 1029 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 1030 TestMediaAudioRequestStatusCallback callback = requestToPlayMediaInPrimaryZone(info); 1031 mRequestCallback.receivedMediaRequest(); 1032 1033 boolean succeeded = mCarAudioManager.allowMediaAudioOnPrimaryZone(mMediaRequestId, 1034 /* allow= */ false); 1035 1036 callback.receivedApproval(); 1037 long tempRequestId = mMediaRequestId; 1038 mMediaRequestId = INVALID_REQUEST_ID; 1039 assertWithMessage("Unapproved results for request in primary zone") 1040 .that(succeeded).isTrue(); 1041 assertWithMessage("Unapproved request id in primary zone") 1042 .that(callback.mRequestId).isEqualTo(tempRequestId); 1043 assertWithMessage("Unapproved audio status in primary zone").that(callback.mStatus) 1044 .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED); 1045 } 1046 1047 @Test 1048 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1049 @ApiTest(apis = {"android.car.media.CarAudioManager" 1050 + "#allowMediaAudioOnPrimaryZone"}) allowMediaAudioOnPrimaryZone_withInvalidRequestId()1051 public void allowMediaAudioOnPrimaryZone_withInvalidRequestId() throws Exception { 1052 assumePassengerWithValidAudioZone(); 1053 setupMediaAudioRequestCallback(); 1054 1055 boolean succeeded = mCarAudioManager 1056 .allowMediaAudioOnPrimaryZone(INVALID_REQUEST_ID, /* allow= */ true); 1057 1058 assertWithMessage("Invalid request id allowed results") 1059 .that(succeeded).isFalse(); 1060 } 1061 1062 @Test 1063 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1064 @ApiTest(apis = {"android.car.media.CarAudioManager" 1065 + "#cancelMediaAudioOnPrimaryZone"}) cancelMediaAudioOnPrimaryZone()1066 public void cancelMediaAudioOnPrimaryZone() throws Exception { 1067 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 1068 setupMediaAudioRequestCallback(); 1069 OccupantZoneInfo info = 1070 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 1071 TestMediaAudioRequestStatusCallback callback = requestToPlayMediaInPrimaryZone(info); 1072 mRequestCallback.receivedMediaRequest(); 1073 1074 mCarAudioManager.cancelMediaAudioOnPrimaryZone(mMediaRequestId); 1075 1076 mMediaRequestId = INVALID_REQUEST_ID; 1077 callback.receivedApproval(); 1078 assertWithMessage("Cancelled audio status in primary zone") 1079 .that(callback.mStatus).isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_CANCELLED); 1080 } 1081 1082 @Test 1083 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1084 @ApiTest(apis = {"android.car.media.CarAudioManager" 1085 + "#resetMediaAudioOnPrimaryZone"}) resetMediaAudioOnPrimaryZone()1086 public void resetMediaAudioOnPrimaryZone() throws Exception { 1087 int passengerAudioZoneId = assumePassengerWithValidAudioZone(); 1088 setupMediaAudioRequestCallback(); 1089 OccupantZoneInfo info = 1090 mCarOccupantZoneManager.getOccupantForAudioZoneId(passengerAudioZoneId); 1091 TestMediaAudioRequestStatusCallback callback = requestToPlayMediaInPrimaryZone(info); 1092 mRequestCallback.receivedMediaRequest(); 1093 mCarAudioManager.allowMediaAudioOnPrimaryZone(mMediaRequestId, /* allow= */ true); 1094 callback.receivedApproval(); 1095 callback.reset(); 1096 1097 mCarAudioManager.resetMediaAudioOnPrimaryZone(info); 1098 1099 long tempRequestId = mMediaRequestId; 1100 mMediaRequestId = INVALID_REQUEST_ID; 1101 callback.receivedApproval(); 1102 assertWithMessage("Reset request id in primary zone") 1103 .that(callback.mRequestId).isEqualTo(tempRequestId); 1104 assertWithMessage("Reset audio status in primary zone") 1105 .that(callback.mStatus).isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); 1106 } 1107 1108 @Test 1109 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1110 @ApiTest(apis = {"android.car.media.CarAudioManager#getCurrentAudioZoneConfigInfo"}) getCurrentAudioZoneConfigInfo()1111 public void getCurrentAudioZoneConfigInfo() { 1112 assumeDynamicRoutingIsEnabled(); 1113 List<TestZoneConfigIdInfo> zoneConfigs = assumeSecondaryZoneConfigs(); 1114 1115 CarAudioZoneConfigInfo currentZoneConfigInfo = 1116 mCarAudioManager.getCurrentAudioZoneConfigInfo(mZoneId); 1117 1118 assertWithMessage("Current zone config info") 1119 .that(TestZoneConfigIdInfo.getZoneConfigFromInfo(currentZoneConfigInfo)) 1120 .isIn(zoneConfigs); 1121 } 1122 1123 @Test 1124 @EnsureHasPermission({Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, 1125 Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME}) 1126 @ApiTest(apis = {"android.car.media.CarAudioManager#getCurrentAudioZoneConfigInfo", 1127 "android.car.media.CarAudioZoneConfigInfo#isActive", 1128 "android.car.media.CarAudioZoneConfigInfo#isSelected", 1129 "android.car.media.CarAudioZoneConfigInfo#isDefault", 1130 "android.car.media.CarAudioZoneConfigInfo#getConfigVolumeGroups"}) 1131 @RequiresFlagsEnabled(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES) getCurrentAudioZoneConfigInfo_withDynamicDevicesEnabled()1132 public void getCurrentAudioZoneConfigInfo_withDynamicDevicesEnabled() throws Exception { 1133 assumeDynamicRoutingIsEnabled(); 1134 List<TestZoneConfigIdInfo> zoneConfigs = assumeSecondaryZoneConfigs(); 1135 setUpDefaultCarAudioConfigurationForZone(mZoneId); 1136 1137 CarAudioZoneConfigInfo currentZoneConfigInfo = 1138 mCarAudioManager.getCurrentAudioZoneConfigInfo(mZoneId); 1139 1140 assertWithMessage("Current zone config info, with dynamic device enabled") 1141 .that(TestZoneConfigIdInfo.getZoneConfigFromInfo(currentZoneConfigInfo)) 1142 .isIn(zoneConfigs); 1143 assertWithMessage("Current zone config info active status") 1144 .that(currentZoneConfigInfo.isActive()).isTrue(); 1145 assertWithMessage("Current zone config info selected status") 1146 .that(currentZoneConfigInfo.isSelected()).isTrue(); 1147 assertWithMessage("Current zone config info default indicator") 1148 .that(currentZoneConfigInfo.isDefault()).isFalse(); 1149 List<CarVolumeGroupInfo> currentInfos = 1150 mCarAudioManager.getVolumeGroupInfosForZone(mZoneId); 1151 for (CarVolumeGroupInfo info : currentInfos) { 1152 assertWithMessage("Current zone config info volume group %s", info.getId()) 1153 .that(currentZoneConfigInfo.getConfigVolumeGroups()).contains(info); 1154 } 1155 } 1156 1157 @Test 1158 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1159 @ApiTest(apis = {"android.car.media.CarAudioManager#getCurrentAudioZoneConfigInfo"}) getCurrentAudioZoneConfigInfo_withInvalidZoneId_fails()1160 public void getCurrentAudioZoneConfigInfo_withInvalidZoneId_fails() { 1161 assumeDynamicRoutingIsEnabled(); 1162 1163 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 1164 () -> mCarAudioManager.getCurrentAudioZoneConfigInfo(INVALID_AUDIO_ZONE)); 1165 1166 assertThat(exception).hasMessageThat().contains("Invalid audio zone Id"); 1167 } 1168 1169 @Test 1170 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1171 @ApiTest(apis = {"android.car.media.CarAudioManager#getAudioZoneConfigInfos"}) getAudioZoneConfigInfos_forPrimaryZone()1172 public void getAudioZoneConfigInfos_forPrimaryZone() { 1173 assumeDynamicRoutingIsEnabled(); 1174 List<TestZoneConfigIdInfo> primaryZoneConfigsFromDump = parsePrimaryZoneConfigs(); 1175 1176 List<CarAudioZoneConfigInfo> zoneConfigInfos = 1177 mCarAudioManager.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE); 1178 1179 assertWithMessage("Primary audio zone config") 1180 .that(TestZoneConfigIdInfo.getZoneConfigListFromInfoList(zoneConfigInfos)) 1181 .containsExactlyElementsIn(primaryZoneConfigsFromDump); 1182 } 1183 1184 @Test 1185 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1186 @ApiTest(apis = {"android.car.media.CarAudioManager#getAudioZoneConfigInfos"}) getAudioZoneConfigInfos_forSecondaryZone()1187 public void getAudioZoneConfigInfos_forSecondaryZone() { 1188 assumeDynamicRoutingIsEnabled(); 1189 List<TestZoneConfigIdInfo> zoneConfigs = assumeSecondaryZoneConfigs(); 1190 1191 List<CarAudioZoneConfigInfo> zoneConfigInfosFromDump = 1192 mCarAudioManager.getAudioZoneConfigInfos(mZoneId); 1193 1194 assertWithMessage("All zone config infos") 1195 .that(TestZoneConfigIdInfo.getZoneConfigListFromInfoList(zoneConfigInfosFromDump)) 1196 .containsExactlyElementsIn(zoneConfigs); 1197 } 1198 1199 @Test 1200 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1201 @ApiTest(apis = {"android.car.media.CarAudioManager#getAudioZoneConfigInfos"}) getAudioZoneConfigInfos_withInvalidZoneId_fails()1202 public void getAudioZoneConfigInfos_withInvalidZoneId_fails() { 1203 assumeDynamicRoutingIsEnabled(); 1204 1205 IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, 1206 () -> mCarAudioManager.getAudioZoneConfigInfos(INVALID_AUDIO_ZONE)); 1207 1208 assertThat(exception).hasMessageThat().contains("Invalid audio zone Id"); 1209 } 1210 1211 @Test 1212 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1213 @ApiTest(apis = {"android.car.media.CarAudioManager#switchAudioZoneToConfig"}) 1214 @RequiresFlagsDisabled(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES) switchAudioZoneToConfig()1215 public void switchAudioZoneToConfig() throws Exception { 1216 assumeDynamicRoutingIsEnabled(); 1217 assumeSecondaryZoneConfigs(); 1218 CarAudioZoneConfigInfo zoneConfigInfoSaved = 1219 mCarAudioManager.getCurrentAudioZoneConfigInfo(mZoneId); 1220 CarAudioZoneConfigInfo zoneConfigInfoSwitchedTo = getNonCurrentZoneConfig(mZoneId); 1221 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1222 TestSwitchAudioZoneConfigCallback callback = new TestSwitchAudioZoneConfigCallback(); 1223 1224 mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSwitchedTo, callbackExecutor, 1225 callback); 1226 1227 callback.receivedApproval(); 1228 assertWithMessage("Zone configuration switching status") 1229 .that(callback.mIsSuccessful).isTrue(); 1230 assertWithMessage("Updated zone configuration") 1231 .that(callback.mZoneConfigInfo).isEqualTo(zoneConfigInfoSwitchedTo); 1232 callback.reset(); 1233 mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSaved, callbackExecutor, callback); 1234 callback.receivedApproval(); 1235 } 1236 1237 @Test 1238 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1239 @ApiTest(apis = {"android.car.media.CarAudioManager#switchAudioZoneToConfig", 1240 "android.car.media.CarAudioZoneConfigInfo#isActive", 1241 "android.car.media.CarAudioZoneConfigInfo#isSelected", 1242 "android.car.media.CarAudioZoneConfigInfo#getConfigVolumeGroups"}) 1243 @RequiresFlagsEnabled(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES) switchAudioZoneToConfig_withDynamicDevicesEnabled()1244 public void switchAudioZoneToConfig_withDynamicDevicesEnabled() throws Exception { 1245 assumeDynamicRoutingIsEnabled(); 1246 assumeSecondaryZoneConfigs(); 1247 CarAudioZoneConfigInfo zoneConfigInfoSaved = 1248 mCarAudioManager.getCurrentAudioZoneConfigInfo(mZoneId); 1249 CarAudioZoneConfigInfo zoneConfigInfoSwitchedTo = getNonCurrentZoneConfig(mZoneId); 1250 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1251 TestSwitchAudioZoneConfigCallback callback = new TestSwitchAudioZoneConfigCallback(); 1252 1253 mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSwitchedTo, callbackExecutor, 1254 callback); 1255 1256 callback.receivedApproval(); 1257 assertWithMessage("Zone configuration switching status with dynamic devices enabled") 1258 .that(callback.mIsSuccessful).isTrue(); 1259 assertWithMessage("Updated zone configuration with dynamic devices enabled") 1260 .that(callback.mZoneConfigInfo.hasSameConfigInfo(zoneConfigInfoSwitchedTo)) 1261 .isTrue(); 1262 assertWithMessage("Switched configuration active status with dynamic devices enable") 1263 .that(callback.mZoneConfigInfo.isActive()).isTrue(); 1264 assertWithMessage("Switched configuration selected status with dynamic devices enable") 1265 .that(callback.mZoneConfigInfo.isSelected()).isTrue(); 1266 CarAudioZoneConfigInfo updatedPreviousConfig = 1267 mCarAudioManager.getAudioZoneConfigInfos(mZoneId).stream() 1268 .filter(info -> info.getConfigId() == zoneConfigInfoSaved.getConfigId()) 1269 .findFirst().orElseThrow(); 1270 assertWithMessage("Previous configuration selected status with dynamic devices enable") 1271 .that(updatedPreviousConfig.isSelected()).isFalse(); 1272 callback.reset(); 1273 mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSaved, callbackExecutor, callback); 1274 callback.receivedApproval(); 1275 } 1276 1277 @Test 1278 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1279 @ApiTest(apis = {"android.car.media.CarAudioManager#switchAudioZoneToConfig"}) switchAudioZoneToConfig_withNullConfig_fails()1280 public void switchAudioZoneToConfig_withNullConfig_fails() throws Exception { 1281 assumeDynamicRoutingIsEnabled(); 1282 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1283 TestSwitchAudioZoneConfigCallback callback = new TestSwitchAudioZoneConfigCallback(); 1284 1285 NullPointerException exception = assertThrows(NullPointerException.class, 1286 () -> mCarAudioManager.switchAudioZoneToConfig(/* zoneConfig= */ null, 1287 callbackExecutor, callback)); 1288 1289 assertThat(exception).hasMessageThat().contains("Audio zone configuration can not be null"); 1290 } 1291 1292 @Test 1293 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1294 @ApiTest(apis = {"android.car.media.CarAudioManager#switchAudioZoneToConfig"}) switchAudioZoneToConfig_withNullExecutor_fails()1295 public void switchAudioZoneToConfig_withNullExecutor_fails() throws Exception { 1296 assumeDynamicRoutingIsEnabled(); 1297 assumeSecondaryZoneConfigs(); 1298 CarAudioZoneConfigInfo zoneConfigInfoSwitchedTo = getNonCurrentZoneConfig(mZoneId); 1299 TestSwitchAudioZoneConfigCallback callback = new TestSwitchAudioZoneConfigCallback(); 1300 1301 NullPointerException exception = assertThrows(NullPointerException.class, 1302 () -> mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSwitchedTo, 1303 /* executor= */ null, callback)); 1304 1305 assertThat(exception).hasMessageThat().contains("Executor can not be null"); 1306 } 1307 1308 @Test 1309 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1310 @ApiTest(apis = {"android.car.media.CarAudioManager#switchAudioZoneToConfig"}) switchAudioZoneToConfig_withNullCallback_fails()1311 public void switchAudioZoneToConfig_withNullCallback_fails() throws Exception { 1312 assumeDynamicRoutingIsEnabled(); 1313 assumeSecondaryZoneConfigs(); 1314 CarAudioZoneConfigInfo zoneConfigInfoSwitchedTo = getNonCurrentZoneConfig(mZoneId); 1315 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1316 1317 NullPointerException exception = assertThrows(NullPointerException.class, 1318 () -> mCarAudioManager.switchAudioZoneToConfig(zoneConfigInfoSwitchedTo, 1319 callbackExecutor, /* callback= */ null)); 1320 1321 assertThat(exception).hasMessageThat().contains("callback can not be null"); 1322 } 1323 1324 @Test 1325 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1326 @ApiTest(apis = {"android.car.media.CarAudioManager" 1327 + "#setAudioZoneMirrorStatusCallback"}) setAudioZoneMirrorStatusCallback()1328 public void setAudioZoneMirrorStatusCallback() { 1329 assumeAudioMirrorEnabled(); 1330 assumePassengersForAudioMirror(); 1331 Executor executor = Executors.newFixedThreadPool(1); 1332 TestAudioZonesMirrorStatusCallback callback; 1333 boolean registered = false; 1334 1335 try { 1336 callback = new TestAudioZonesMirrorStatusCallback(); 1337 registered = mCarAudioManager.setAudioZoneMirrorStatusCallback(executor, callback); 1338 } finally { 1339 if (registered) { 1340 mCarAudioManager.clearAudioZonesMirrorStatusCallback(); 1341 } 1342 } 1343 1344 assertWithMessage("Audio zone mirror status callback registered status") 1345 .that(registered).isTrue(); 1346 } 1347 1348 @Test 1349 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1350 @ApiTest(apis = {"android.car.media.CarAudioManager#enableMirrorForAudioZones"}) enableMirrorForAudioZones()1351 public void enableMirrorForAudioZones() throws Exception { 1352 assumeAudioMirrorEnabled(); 1353 List<Integer> audioZones = assumePassengersForAudioMirror(); 1354 setupAudioMirrorStatusCallback(); 1355 1356 mMirrorRequestId = mCarAudioManager.enableMirrorForAudioZones(audioZones); 1357 1358 mAudioZonesMirrorCallback.waitForCallback(); 1359 assertWithMessage("Enabled mirror for audio zone status") 1360 .that(mAudioZonesMirrorCallback.mStatus).isEqualTo( 1361 CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); 1362 assertWithMessage("Enabled mirror audio zones") 1363 .that(mAudioZonesMirrorCallback.mAudioZones).containsExactlyElementsIn(audioZones); 1364 } 1365 1366 @Test 1367 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1368 @ApiTest(apis = {"android.car.media.CarAudioManager#enableMirrorForAudioZones"}) enableMirrorForAudioZones_withNullList()1369 public void enableMirrorForAudioZones_withNullList() throws Exception { 1370 assumeAudioMirrorEnabled(); 1371 setupAudioMirrorStatusCallback(); 1372 1373 NullPointerException thrown = assertThrows(NullPointerException.class, () -> 1374 mMirrorRequestId = mCarAudioManager 1375 .enableMirrorForAudioZones(/* audioZonesToMirror= */ null)); 1376 1377 assertWithMessage("Null enable mirror audio zones exception") 1378 .that(thrown).hasMessageThat().contains("Audio zones to mirror"); 1379 } 1380 1381 @Test 1382 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1383 @ApiTest(apis = {"android.car.media.CarAudioManager#disableAudioMirrorForZone"}) disableAudioMirrorForZone()1384 public void disableAudioMirrorForZone() throws Exception { 1385 assumeAudioMirrorEnabled(); 1386 List<Integer> audioZones = assumePassengersForAudioMirror(); 1387 int zoneToDisable = audioZones.get(0); 1388 setupAudioMirrorStatusCallback(); 1389 mMirrorRequestId = mCarAudioManager.enableMirrorForAudioZones(audioZones); 1390 mAudioZonesMirrorCallback.waitForCallback(); 1391 mAudioZonesMirrorCallback.reset(); 1392 1393 mCarAudioManager.disableAudioMirrorForZone(zoneToDisable); 1394 1395 mMirrorRequestId = INVALID_REQUEST_ID; 1396 mAudioZonesMirrorCallback.waitForCallback(); 1397 assertWithMessage("Disable mirror status for audio zone %s", zoneToDisable) 1398 .that(mAudioZonesMirrorCallback.mStatus).isEqualTo( 1399 CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); 1400 assertWithMessage("Disable mirror zones for audio zone %s", zoneToDisable) 1401 .that(mAudioZonesMirrorCallback.mAudioZones).containsExactlyElementsIn(audioZones); 1402 } 1403 1404 @Test 1405 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1406 @ApiTest(apis = {"android.car.media.CarAudioManager#disableAudioMirror"}) disableAudioMirror()1407 public void disableAudioMirror() throws Exception { 1408 assumeAudioMirrorEnabled(); 1409 List<Integer> audioZones = assumePassengersForAudioMirror(); 1410 setupAudioMirrorStatusCallback(); 1411 mMirrorRequestId = mCarAudioManager.enableMirrorForAudioZones(audioZones); 1412 mAudioZonesMirrorCallback.waitForCallback(); 1413 mAudioZonesMirrorCallback.reset(); 1414 1415 mCarAudioManager.disableAudioMirror(mMirrorRequestId); 1416 1417 mMirrorRequestId = INVALID_REQUEST_ID; 1418 mAudioZonesMirrorCallback.waitForCallback(); 1419 assertWithMessage("Disable mirror status for audio zones") 1420 .that(mAudioZonesMirrorCallback.mStatus).isEqualTo( 1421 CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); 1422 assertWithMessage("Disable mirror zones for audio zones") 1423 .that(mAudioZonesMirrorCallback.mAudioZones).containsExactlyElementsIn(audioZones); 1424 } 1425 1426 @Test 1427 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1428 @ApiTest(apis = {"android.car.media.CarAudioManager#getMirrorAudioZonesForAudioZone"}) getMirrorAudioZonesForAudioZone()1429 public void getMirrorAudioZonesForAudioZone() throws Exception { 1430 assumeAudioMirrorEnabled(); 1431 List<Integer> audioZones = assumePassengersForAudioMirror(); 1432 int zoneToQuery = audioZones.get(0); 1433 setupAudioMirrorStatusCallback(); 1434 mMirrorRequestId = mCarAudioManager.enableMirrorForAudioZones(audioZones); 1435 mAudioZonesMirrorCallback.waitForCallback(); 1436 1437 List<Integer> queriedZones = mCarAudioManager.getMirrorAudioZonesForAudioZone(zoneToQuery); 1438 1439 assertWithMessage("Queried audio zones").that(queriedZones) 1440 .containsExactlyElementsIn(audioZones); 1441 } 1442 1443 @Test 1444 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS) 1445 @ApiTest(apis = {"android.car.media.CarAudioManager#getMirrorAudioZonesForMirrorRequest"}) getMirrorAudioZonesForMirrorRequest()1446 public void getMirrorAudioZonesForMirrorRequest() throws Exception { 1447 assumeAudioMirrorEnabled(); 1448 List<Integer> audioZones = assumePassengersForAudioMirror(); 1449 setupAudioMirrorStatusCallback(); 1450 mMirrorRequestId = mCarAudioManager.enableMirrorForAudioZones(audioZones); 1451 mAudioZonesMirrorCallback.waitForCallback(); 1452 1453 List<Integer> queriedZones = mCarAudioManager.getMirrorAudioZonesForMirrorRequest( 1454 mMirrorRequestId); 1455 1456 assertWithMessage("Queried audio zones for request %s", mMirrorRequestId).that(queriedZones) 1457 .containsExactlyElementsIn(audioZones); 1458 } 1459 requestToPlayMediaInPrimaryZone( OccupantZoneInfo info)1460 private TestMediaAudioRequestStatusCallback requestToPlayMediaInPrimaryZone( 1461 OccupantZoneInfo info) { 1462 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1463 TestMediaAudioRequestStatusCallback callback = new TestMediaAudioRequestStatusCallback(); 1464 mMediaRequestId = 1465 mCarAudioManager.requestMediaAudioOnPrimaryZone(info, callbackExecutor, callback); 1466 return callback; 1467 } 1468 setupMediaAudioRequestCallback()1469 private void setupMediaAudioRequestCallback() { 1470 Executor requestExecutor = Executors.newFixedThreadPool(1); 1471 mRequestCallback = new TestPrimaryZoneMediaAudioRequestStatusCallback(); 1472 mCarAudioManager.setPrimaryZoneMediaAudioRequestCallback(requestExecutor, mRequestCallback); 1473 } 1474 setupAudioMirrorStatusCallback()1475 private void setupAudioMirrorStatusCallback() { 1476 Executor executor = Executors.newFixedThreadPool(1); 1477 mAudioZonesMirrorCallback = new TestAudioZonesMirrorStatusCallback(); 1478 mCarAudioManager.setAudioZoneMirrorStatusCallback(executor, mAudioZonesMirrorCallback); 1479 } 1480 assumePassengerWithValidAudioZone()1481 private int assumePassengerWithValidAudioZone() { 1482 List<Integer> audioZonesWithPassengers = assumePassengersWithValidAudioZones( 1483 /* count= */ 1, "Audio share to primary zone"); 1484 1485 return audioZonesWithPassengers.get(0); 1486 } 1487 assumePassengersWithValidAudioZones(int minimumCount, String message)1488 private List<Integer> assumePassengersWithValidAudioZones(int minimumCount, String message) { 1489 List<Integer> audioZonesWithPassengers = getAvailablePassengerAudioZone(); 1490 assumeTrue(message + ": Need at least " + minimumCount 1491 + " passenger(s) with valid audio zone id", 1492 audioZonesWithPassengers.size() >= minimumCount); 1493 1494 return audioZonesWithPassengers; 1495 } 1496 assumePassengersForAudioMirror()1497 private List<Integer> assumePassengersForAudioMirror() { 1498 List<Integer> audioZonesWithPassengers = assumePassengersWithValidAudioZones(/* count= */ 2, 1499 "Passenger audio mirror"); 1500 1501 return audioZonesWithPassengers.subList(/* fromIndex= */ 0, /* toIndex= */ 2); 1502 } 1503 getAvailablePassengerAudioZone()1504 private List<Integer> getAvailablePassengerAudioZone() { 1505 return mCarOccupantZoneManager.getAllOccupantZones().stream() 1506 .filter(occupant -> mCarOccupantZoneManager.getUserForOccupant(occupant) 1507 != CarOccupantZoneManager.INVALID_USER_ID) 1508 .map(occupant -> mCarOccupantZoneManager.getAudioZoneIdForOccupant(occupant)) 1509 .filter(audioZoneId -> audioZoneId != INVALID_AUDIO_ZONE 1510 && audioZoneId != PRIMARY_AUDIO_ZONE) 1511 .collect(Collectors.toList()); 1512 } 1513 assumeSecondaryZoneConfigs()1514 private List<TestZoneConfigIdInfo> assumeSecondaryZoneConfigs() { 1515 List<Integer> audioZonesWithPassengers = getAvailablePassengerAudioZone(); 1516 assumeFalse("Requires a zone with a passenger/user", audioZonesWithPassengers.isEmpty()); 1517 SparseArray<List<TestZoneConfigIdInfo>> zoneConfigs = parseAudioZoneConfigs(); 1518 List<TestZoneConfigIdInfo> secondaryZoneConfigs = null; 1519 for (int index = 0; index < audioZonesWithPassengers.size(); index++) { 1520 int zoneId = audioZonesWithPassengers.get(index); 1521 if (zoneConfigs.contains(zoneId) && zoneConfigs.get(zoneId).size() > 1) { 1522 mZoneId = zoneId; 1523 secondaryZoneConfigs = zoneConfigs.get(zoneId); 1524 break; 1525 } 1526 } 1527 assumeTrue("Secondary zones requires multiple zone configurations", 1528 secondaryZoneConfigs != null); 1529 return secondaryZoneConfigs; 1530 } 1531 parsePrimaryZoneConfigs()1532 private List<TestZoneConfigIdInfo> parsePrimaryZoneConfigs() { 1533 SparseArray<List<TestZoneConfigIdInfo>> zoneConfigs = parseAudioZoneConfigs(); 1534 List<TestZoneConfigIdInfo> primaryZoneConfigs = zoneConfigs.get(PRIMARY_AUDIO_ZONE); 1535 assertWithMessage("Dumped primary audio zone configuration") 1536 .that(primaryZoneConfigs).isNotNull(); 1537 return primaryZoneConfigs; 1538 } 1539 parseAudioZoneConfigs()1540 private SparseArray<List<TestZoneConfigIdInfo>> parseAudioZoneConfigs() { 1541 SparseArray<List<TestZoneConfigIdInfo>> zoneConfigs = new SparseArray<>(); 1542 if (Flags.carDumpToProto()) { 1543 List<CarAudioZoneProto> zoneProtoList = mCarAudioServiceProtoDump 1544 .getCarAudioZonesList(); 1545 for (int zoneIndex = 0; zoneIndex < zoneProtoList.size(); zoneIndex++) { 1546 int zoneId = zoneProtoList.get(zoneIndex).getId(); 1547 List<CarAudioZoneConfigProto> zoneConfigProtoList = zoneProtoList.get(zoneIndex) 1548 .getZoneConfigsList(); 1549 for (int configIndex = 0; configIndex < zoneConfigProtoList.size(); configIndex++) { 1550 if (!zoneConfigs.contains(zoneId)) { 1551 zoneConfigs.put(zoneId, new ArrayList<>()); 1552 } 1553 int zoneConfigId = zoneConfigProtoList.get(configIndex).getId(); 1554 String configName = zoneConfigProtoList.get(configIndex).getName(); 1555 zoneConfigs.get(zoneId).add(new TestZoneConfigIdInfo(zoneId, zoneConfigId, 1556 configName)); 1557 } 1558 } 1559 } else { 1560 Matcher zoneConfigMatcher = ZONE_CONFIG_PATTERN.matcher(mCarAudioServiceDump); 1561 while (zoneConfigMatcher.find()) { 1562 int zoneId = Integer.parseInt(zoneConfigMatcher.group(3)); 1563 int zoneConfigId = Integer.parseInt(zoneConfigMatcher.group(2)); 1564 String configName = zoneConfigMatcher.group(1); 1565 if (!zoneConfigs.contains(zoneId)) { 1566 zoneConfigs.put(zoneId, new ArrayList<>()); 1567 } 1568 zoneConfigs.get(zoneId).add(new TestZoneConfigIdInfo(zoneId, zoneConfigId, 1569 configName)); 1570 } 1571 } 1572 return zoneConfigs; 1573 } 1574 getNonCurrentZoneConfig(int zoneId)1575 private CarAudioZoneConfigInfo getNonCurrentZoneConfig(int zoneId) { 1576 List<CarAudioZoneConfigInfo> zoneConfigInfos = 1577 mCarAudioManager.getAudioZoneConfigInfos(zoneId); 1578 CarAudioZoneConfigInfo currentZoneConfigInfo = 1579 mCarAudioManager.getCurrentAudioZoneConfigInfo(zoneId); 1580 1581 CarAudioZoneConfigInfo differentZoneConfig = null; 1582 for (int index = 0; index < zoneConfigInfos.size(); index++) { 1583 if (!currentZoneConfigInfo.equals(zoneConfigInfos.get(index))) { 1584 differentZoneConfig = zoneConfigInfos.get(index); 1585 break; 1586 } 1587 } 1588 1589 return differentZoneConfig; 1590 } 1591 1592 @Test 1593 @ApiTest(apis = {"android.car.media.CarAudioManager" 1594 + "#registerCarVolumeGroupEventCallback"}) registerCarVolumeGroupEventCallback_nullCallback_throwsNPE()1595 public void registerCarVolumeGroupEventCallback_nullCallback_throwsNPE() { 1596 Executor executor = Executors.newFixedThreadPool(1); 1597 1598 NullPointerException exception = assertThrows(NullPointerException.class, 1599 () -> mCarAudioManager.registerCarVolumeGroupEventCallback(executor, 1600 /* callback= */ null)); 1601 1602 assertWithMessage("Register car volume group event with null callback exception") 1603 .that(exception).hasMessageThat() 1604 .contains("Car volume event callback can not be null"); 1605 } 1606 1607 @Test 1608 @ApiTest(apis = {"android.car.media.CarAudioManager" 1609 + "#registerCarVolumeGroupEventCallback"}) registerCarVolumeGroupEventCallback_nullExecutor_throwsNPE()1610 public void registerCarVolumeGroupEventCallback_nullExecutor_throwsNPE() { 1611 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1612 1613 NullPointerException exception = assertThrows(NullPointerException.class, 1614 () -> mCarAudioManager.registerCarVolumeGroupEventCallback(/* executor= */ null, 1615 mEventCallback)); 1616 1617 mEventCallback = null; 1618 assertWithMessage("Register car volume group event with null executor exception") 1619 .that(exception).hasMessageThat().contains("Executor can not be null"); 1620 } 1621 1622 @Test 1623 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1624 @ApiTest(apis = {"android.car.media.CarAudioManager" 1625 + "#registerCarVolumeGroupEventCallback"}) registerCarVolumeGroupEventCallback_volumeGroupEventsDisabled()1626 public void registerCarVolumeGroupEventCallback_volumeGroupEventsDisabled() throws Exception { 1627 assumeDynamicRoutingIsEnabled(); 1628 assumeVolumeGroupEventsIsDisabled(); 1629 Executor executor = Executors.newFixedThreadPool(1); 1630 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1631 1632 Exception exception = assertThrows(IllegalStateException.class, 1633 () -> mCarAudioManager.registerCarVolumeGroupEventCallback(executor, 1634 mEventCallback)); 1635 1636 mEventCallback = null; 1637 assertWithMessage("Register car volume group event with feature disabled") 1638 .that(exception).hasMessageThat().contains("Car Volume Group Event is required"); 1639 } 1640 1641 @Test 1642 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1643 @ApiTest(apis = { 1644 "android.car.media.CarAudioManager#registerCarVolumeGroupEventCallback"}) registerCarVolumeGroupEventCallback_onVolumeGroupEvent()1645 public void registerCarVolumeGroupEventCallback_onVolumeGroupEvent() throws Exception { 1646 assumeDynamicRoutingIsEnabled(); 1647 assumeVolumeGroupEventsIsEnabled(); 1648 Executor executor = Executors.newFixedThreadPool(1); 1649 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1650 1651 boolean status = mCarAudioManager.registerCarVolumeGroupEventCallback(executor, 1652 mEventCallback); 1653 1654 injectVolumeUpKeyEvent(); 1655 assertWithMessage("Car volume group event callback") 1656 .that(mEventCallback.receivedVolumeGroupEvents()).isTrue(); 1657 } 1658 1659 @Test 1660 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1661 @ApiTest(apis = {"android.car.media.CarAudioManager" 1662 + "#registerCarVolumeGroupEventCallback"}) registerCarVolumeGroupEventCallback_registerCarVolumeCallback_onVolumeGroupEvent()1663 public void registerCarVolumeGroupEventCallback_registerCarVolumeCallback_onVolumeGroupEvent() 1664 throws Exception { 1665 assumeDynamicRoutingIsEnabled(); 1666 assumeVolumeGroupEventsIsEnabled(); 1667 Executor executor = Executors.newFixedThreadPool(1); 1668 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1669 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 1670 mCarAudioManager.registerCarVolumeGroupEventCallback(executor, mEventCallback); 1671 1672 mCarAudioManager.registerCarVolumeCallback(mCallback); 1673 1674 injectVolumeDownKeyEvent(); 1675 assertWithMessage("Car volume group event for registered callback") 1676 .that(mEventCallback.receivedVolumeGroupEvents()).isTrue(); 1677 assertWithMessage("Car group volume changed for deprioritized callback") 1678 .that(mCallback.receivedGroupVolumeChanged()).isFalse(); 1679 } 1680 1681 @Test 1682 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1683 @ApiTest(apis = {"android.car.media.CarAudioManager" 1684 + "#registerCarVolumeGroupEventCallback", 1685 "android.car.media.CarAudioManager" 1686 + "#unregisterCarVolumeGroupEventCallback"}) unregisterCarVolumeGroupEventCallback_onGroupVolumeChanged()1687 public void unregisterCarVolumeGroupEventCallback_onGroupVolumeChanged() 1688 throws Exception { 1689 assumeDynamicRoutingIsEnabled(); 1690 assumeVolumeGroupEventsIsEnabled(); 1691 Executor executor = Executors.newFixedThreadPool(1); 1692 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1693 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 1694 mCarAudioManager.registerCarVolumeGroupEventCallback(executor, mEventCallback); 1695 mCarAudioManager.registerCarVolumeCallback(mCallback); 1696 1697 mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback); 1698 1699 injectVolumeUpKeyEvent(); 1700 assertWithMessage("Car volume group event for unregistered callback") 1701 .that(mEventCallback.receivedVolumeGroupEvents()).isFalse(); 1702 assertWithMessage("Car group volume changed for reprioritized callback") 1703 .that(mCallback.receivedGroupVolumeChanged()).isTrue(); 1704 } 1705 1706 @Test 1707 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1708 @ApiTest(apis = {"android.car.media.CarAudioManager" 1709 + "#registerCarVolumeGroupEventCallback", 1710 "android.car.media.CarAudioManager" 1711 + "#unregisterCarVolumeGroupEventCallback"}) reRegisterCarVolumeGroupEventCallback_eventCallbackReprioritized()1712 public void reRegisterCarVolumeGroupEventCallback_eventCallbackReprioritized() 1713 throws Exception { 1714 assumeDynamicRoutingIsEnabled(); 1715 assumeVolumeGroupEventsIsEnabled(); 1716 Executor executor = Executors.newFixedThreadPool(1); 1717 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1718 mCallback = new CarAudioManagerTestUtils.SyncCarVolumeCallback(); 1719 mCarAudioManager.registerCarVolumeGroupEventCallback(executor, mEventCallback); 1720 mCarAudioManager.registerCarVolumeCallback(mCallback); 1721 mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback); 1722 1723 mCarAudioManager.registerCarVolumeGroupEventCallback(executor, mEventCallback); 1724 1725 injectVolumeDownKeyEvent(); 1726 assertWithMessage("Car volume group event for re-registered callback") 1727 .that(mEventCallback.receivedVolumeGroupEvents()).isTrue(); 1728 assertWithMessage("Car group volume changed for deprioritized callback") 1729 .that(mCallback.receivedGroupVolumeChanged()).isFalse(); 1730 } 1731 1732 @Test 1733 @ApiTest(apis = {"android.car.media.CarAudioManager" 1734 + "#unregisterCarVolumeGroupEventCallback"}) unregisterCarVolumeGroupEventCallback_nullCallback_throwsNPE()1735 public void unregisterCarVolumeGroupEventCallback_nullCallback_throwsNPE() { 1736 NullPointerException exception = assertThrows(NullPointerException.class, 1737 () -> mCarAudioManager.unregisterCarVolumeGroupEventCallback(/* callback= */ null)); 1738 1739 assertWithMessage("Unregister car volume group event with null callback exception") 1740 .that(exception).hasMessageThat() 1741 .contains("Car volume event callback can not be null"); 1742 } 1743 1744 @Test 1745 @ApiTest(apis = {"android.car.media.CarAudioManager" 1746 + "#unregisterCarVolumeGroupEventCallback"}) unregisterCarVolumeGroupEventCallback_withoutPermission_throws()1747 public void unregisterCarVolumeGroupEventCallback_withoutPermission_throws() 1748 throws Exception { 1749 assumeDynamicRoutingIsEnabled(); 1750 assumeVolumeGroupEventsIsEnabled(); 1751 Executor executor = Executors.newFixedThreadPool(1); 1752 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1753 runWithCarControlAudioVolumePermission( 1754 () -> mCarAudioManager.registerCarVolumeGroupEventCallback(executor, 1755 mEventCallback)); 1756 1757 Exception exception = assertThrows(SecurityException.class, 1758 () -> mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback)); 1759 1760 assertWithMessage("Unregister car volume group event callback without permission exception") 1761 .that(exception).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_VOLUME); 1762 1763 } 1764 1765 @Test 1766 @ApiTest(apis = {"android.car.media.CarAudioManager" 1767 + "#unregisterCarVolumeGroupEventCallback"}) unregisterCarVolumeGroupEventCallback_withoutPermission_receivesCallback()1768 public void unregisterCarVolumeGroupEventCallback_withoutPermission_receivesCallback() 1769 throws Exception { 1770 assumeDynamicRoutingIsEnabled(); 1771 assumeVolumeGroupEventsIsEnabled(); 1772 Executor executor = Executors.newFixedThreadPool(1); 1773 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1774 runWithCarControlAudioVolumePermission( 1775 () -> mCarAudioManager.registerCarVolumeGroupEventCallback(executor, 1776 mEventCallback)); 1777 1778 Exception exception = assertThrows(SecurityException.class, 1779 () -> mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback)); 1780 1781 injectVolumeDownKeyEvent(); 1782 assertWithMessage("Car volume group event after unregister security exception") 1783 .that(mEventCallback.receivedVolumeGroupEvents()).isTrue(); 1784 } 1785 1786 @Test 1787 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1788 @ApiTest(apis = {"android.car.media.CarAudioManager" 1789 + "#registerCarVolumeGroupEventCallback", 1790 "android.car.media.CarAudioManager" 1791 + "#unregisterCarVolumeGroupEventCallback"}) unregisterCarVolumeGroupEventCallback_noLongerReceivesEventCallback()1792 public void unregisterCarVolumeGroupEventCallback_noLongerReceivesEventCallback() 1793 throws Exception { 1794 assumeDynamicRoutingIsEnabled(); 1795 assumeVolumeGroupEventsIsEnabled(); 1796 Executor executor = Executors.newFixedThreadPool(1); 1797 mEventCallback = new CarAudioManagerTestUtils.TestCarVolumeGroupEventCallback(); 1798 mCarAudioManager.registerCarVolumeGroupEventCallback(executor, mEventCallback); 1799 1800 mCarAudioManager.unregisterCarVolumeGroupEventCallback(mEventCallback); 1801 1802 injectVolumeUpKeyEvent(); 1803 assertWithMessage("Car volume group event for unregistered callback") 1804 .that(mEventCallback.receivedVolumeGroupEvents()).isFalse(); 1805 } 1806 1807 @Test 1808 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1809 @ApiTest(apis = {"android.car.media.CarAudioManager#isVolumeGroupMuted", 1810 "android.car.media.CarVolumeGroupInfo#isMuted"}) isVolumeGroupMuted()1811 public void isVolumeGroupMuted() { 1812 assumeDynamicRoutingIsEnabled(); 1813 readFirstZoneAndVolumeGroup(); 1814 CarVolumeGroupInfo volumeGroupInfo = mCarAudioManager.getVolumeGroupInfo(mZoneId, 1815 mVolumeGroupId); 1816 1817 boolean isMuted = mCarAudioManager.isVolumeGroupMuted(mZoneId, mVolumeGroupId); 1818 1819 assertWithMessage("Mute state for zone %s group %s", mZoneId, mVolumeGroupId) 1820 .that(isMuted).isEqualTo(volumeGroupInfo.isMuted()); 1821 } 1822 1823 @Test 1824 @EnsureHasPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME) 1825 @ApiTest(apis = {"android.car.media.CarAudioManager#setVolumeGroupMute", 1826 "android.car.media.CarAudioManager#isVolumeGroupMuted", 1827 "android.car.media.CarVolumeGroupInfo#isMutedBySystem"}) 1828 @RequiresFlagsEnabled(Flags.FLAG_CAR_AUDIO_MUTE_AMBIGUITY) setVolumeGroupMute_withMuteAmbiguityFlagEnabled()1829 public void setVolumeGroupMute_withMuteAmbiguityFlagEnabled() { 1830 assumeDynamicRoutingIsEnabled(); 1831 assumeVolumeGroupMutingIsEnabled(); 1832 readFirstZoneAndVolumeGroup(); 1833 boolean isMuted = mCarAudioManager.isVolumeGroupMuted(mZoneId, mVolumeGroupId); 1834 boolean isMutedBySystem = mCarAudioManager.getVolumeGroupInfo(mZoneId, 1835 mVolumeGroupId).isMutedBySystem(); 1836 String muteOperationStr = isMuted ? "unmuting" : "muting"; 1837 1838 try { 1839 mCarAudioManager.setVolumeGroupMute(mZoneId, mVolumeGroupId, !isMuted, /* flags= */ 0); 1840 1841 assertWithMessage("Mute state for zone %s group %s after %s", mZoneId, mVolumeGroupId, 1842 muteOperationStr) 1843 .that(mCarAudioManager.isVolumeGroupMuted(mZoneId, mVolumeGroupId)) 1844 .isEqualTo(mCarAudioManager.getVolumeGroupInfo(mZoneId, mVolumeGroupId) 1845 .isMuted()); 1846 assertWithMessage("Mute by system state for zone %s group %s after %s", mZoneId, 1847 mVolumeGroupId, muteOperationStr) 1848 .that(mCarAudioManager.getVolumeGroupInfo(mZoneId, mVolumeGroupId) 1849 .isMutedBySystem()).isEqualTo(isMutedBySystem); 1850 } finally { 1851 mCarAudioManager.setVolumeGroupMute(mZoneId, mVolumeGroupId, isMuted, /* flags= */ 0); 1852 } 1853 } 1854 getNumberOfPrimaryZoneAudioMediaCallbacks()1855 private int getNumberOfPrimaryZoneAudioMediaCallbacks() { 1856 if (Flags.carDumpToProto()) { 1857 return mCarAudioServiceProtoDump.getMediaRequestHandler().hasMediaRequestCallbackCount() 1858 ? mCarAudioServiceProtoDump.getMediaRequestHandler() 1859 .getMediaRequestCallbackCount() : 0; 1860 } 1861 Matcher matchCount = PRIMARY_ZONE_MEDIA_REQUEST_APPROVERS_PATTERN 1862 .matcher(mCarAudioServiceDump); 1863 assertWithMessage("No Car Audio Media in dump").that(matchCount.find()).isTrue(); 1864 return Integer.parseInt(matchCount.group(1)); 1865 } 1866 assumeNoPrimaryZoneAudioMediaApprovers()1867 private void assumeNoPrimaryZoneAudioMediaApprovers() { 1868 assumeTrue("Primary zone audio media approvers must be empty", 1869 getNumberOfPrimaryZoneAudioMediaCallbacks() == 0); 1870 } 1871 setUpDefaultCarAudioConfigurationForZone(int zoneId)1872 private void setUpDefaultCarAudioConfigurationForZone(int zoneId) throws Exception { 1873 CarAudioZoneConfigInfo current = 1874 mCarAudioManager.getCurrentAudioZoneConfigInfo(zoneId); 1875 if (current != null && current.isDefault()) { 1876 return; 1877 } 1878 1879 CarAudioZoneConfigInfo defaultConfig = 1880 mCarAudioManager.getAudioZoneConfigInfos(zoneId).stream() 1881 .filter(CarAudioZoneConfigInfo::isDefault).findFirst().orElseThrow(); 1882 Executor callbackExecutor = Executors.newFixedThreadPool(1); 1883 TestSwitchAudioZoneConfigCallback callback = new TestSwitchAudioZoneConfigCallback(); 1884 mCarAudioManager.switchAudioZoneToConfig(defaultConfig, callbackExecutor, callback); 1885 callback.receivedApproval(); 1886 } 1887 assumeDynamicRoutingIsEnabled()1888 private void assumeDynamicRoutingIsEnabled() { 1889 assumeTrue("Requires dynamic audio routing", 1890 mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)); 1891 } 1892 assumeDynamicRoutingIsDisabled()1893 private void assumeDynamicRoutingIsDisabled() { 1894 assumeFalse("Requires dynamic audio routing", 1895 mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)); 1896 } 1897 assumeVolumeGroupMutingIsEnabled()1898 private void assumeVolumeGroupMutingIsEnabled() { 1899 assumeTrue("Requires volume group muting", 1900 mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING)); 1901 } 1902 assumeVolumeGroupMutingIsDisabled()1903 private void assumeVolumeGroupMutingIsDisabled() { 1904 assumeFalse("Requires volume group muting disabled", 1905 mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING)); 1906 } 1907 assumeAudioMirrorEnabled()1908 private void assumeAudioMirrorEnabled() { 1909 assumeTrue("Requires audio mirroring", 1910 mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING)); 1911 } 1912 assumeVolumeGroupEventsIsEnabled()1913 private void assumeVolumeGroupEventsIsEnabled() { 1914 assumeTrue(mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS)); 1915 } 1916 assumeVolumeGroupEventsIsDisabled()1917 private void assumeVolumeGroupEventsIsDisabled() { 1918 assumeFalse(mCarAudioManager.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS)); 1919 } 1920 runWithCarControlAudioVolumePermission(Runnable runnable)1921 private void runWithCarControlAudioVolumePermission(Runnable runnable) { 1922 UI_AUTOMATION.adoptShellPermissionIdentity(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME); 1923 try { 1924 runnable.run(); 1925 } finally { 1926 UI_AUTOMATION.dropShellPermissionIdentity(); 1927 } 1928 } 1929 injectKeyEvent(int keyCode)1930 private void injectKeyEvent(int keyCode) { 1931 long downTime = SystemClock.uptimeMillis(); 1932 KeyEvent volumeDown = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, 1933 keyCode, 0); 1934 UI_AUTOMATION.injectInputEvent(volumeDown, true); 1935 } 1936 injectVolumeDownKeyEvent()1937 private void injectVolumeDownKeyEvent() { 1938 injectKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN); 1939 } 1940 injectVolumeUpKeyEvent()1941 private void injectVolumeUpKeyEvent() { 1942 injectKeyEvent(KeyEvent.KEYCODE_VOLUME_UP); 1943 } 1944 injectVolumeMuteKeyEvent()1945 private void injectVolumeMuteKeyEvent() { 1946 injectKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE); 1947 } 1948 readFirstZoneAndVolumeGroup()1949 private void readFirstZoneAndVolumeGroup() { 1950 if (Flags.carDumpToProto()) { 1951 List<CarAudioZoneProto> zoneProtoList = mCarAudioServiceProtoDump 1952 .getCarAudioZonesList(); 1953 assertWithMessage("No CarAudioZone in proto dump").that(zoneProtoList) 1954 .isNotEmpty(); 1955 mZoneId = zoneProtoList.get(0).getId(); 1956 readFirstVolumeGroupAndVolumeGroupCountFromProto(zoneProtoList.get(0)); 1957 return; 1958 } 1959 Matcher matchZone = ZONE_PATTERN.matcher(mCarAudioServiceDump); 1960 assertWithMessage("No CarAudioZone in dump").that(matchZone.find()).isTrue(); 1961 mZoneId = Integer.parseInt(matchZone.group(1)); 1962 mConfigId = Integer.parseInt(matchZone.group(3)); 1963 readFirstVolumeGroupAndVolumeGroupCount(mZoneId, mConfigId); 1964 } 1965 assumePrimaryZone()1966 private void assumePrimaryZone() { 1967 if (Flags.carDumpToProto()) { 1968 List<CarAudioZoneProto> zoneProtoList = mCarAudioServiceProtoDump 1969 .getCarAudioZonesList(); 1970 for (int zoneIndex = 0; zoneIndex < zoneProtoList.size(); zoneIndex++) { 1971 int zoneId = zoneProtoList.get(zoneIndex).getId(); 1972 if (zoneId == PRIMARY_AUDIO_ZONE) { 1973 mZoneId = zoneId; 1974 readFirstVolumeGroupAndVolumeGroupCountFromProto(zoneProtoList.get(zoneIndex)); 1975 break; 1976 } 1977 } 1978 } else { 1979 Matcher matchZone = ZONE_PATTERN.matcher(mCarAudioServiceDump); 1980 while (matchZone.find()) { 1981 if (Integer.parseInt(matchZone.group(1)) == PRIMARY_AUDIO_ZONE) { 1982 mZoneId = PRIMARY_AUDIO_ZONE; 1983 mConfigId = Integer.parseInt(matchZone.group(3)); 1984 readFirstVolumeGroupAndVolumeGroupCount(mZoneId, mConfigId); 1985 break; 1986 } 1987 } 1988 } 1989 assumeTrue("Primary zone exists", mZoneId == PRIMARY_AUDIO_ZONE); 1990 } 1991 readFirstVolumeGroupAndVolumeGroupCount(int zoneId, int currentConfigId)1992 private void readFirstVolumeGroupAndVolumeGroupCount(int zoneId, int currentConfigId) { 1993 Matcher matchGroup = VOLUME_GROUP_PATTERN.matcher(mCarAudioServiceDump); 1994 boolean findVolumeGroup = false; 1995 mVolumeGroupCount = 0; 1996 while (matchGroup.find()) { 1997 if (Integer.parseInt(matchGroup.group(3)) == zoneId 1998 && Integer.parseInt(matchGroup.group(4)) == currentConfigId) { 1999 if (!findVolumeGroup) { 2000 mVolumeGroupId = Integer.parseInt(matchGroup.group(1)); 2001 findVolumeGroup = true; 2002 } 2003 mVolumeGroupCount++; 2004 } 2005 } 2006 assertWithMessage("No CarVolumeGroup in dump").that(findVolumeGroup).isTrue(); 2007 } 2008 readFirstVolumeGroupAndVolumeGroupCountFromProto(CarAudioZoneProto zoneProto)2009 private void readFirstVolumeGroupAndVolumeGroupCountFromProto(CarAudioZoneProto zoneProto) { 2010 mConfigId = zoneProto.getCurrentZoneConfigId(); 2011 List<CarAudioZoneConfigProto> zoneConfigProtoList = zoneProto.getZoneConfigsList(); 2012 for (int configIndex = 0; configIndex < zoneConfigProtoList.size(); configIndex++) { 2013 if (zoneConfigProtoList.get(configIndex).getId() != mConfigId) { 2014 continue; 2015 } 2016 List<CarVolumeGroupProto> volumeGroupProtoList = zoneConfigProtoList 2017 .get(configIndex).getVolumeGroupsList(); 2018 assertWithMessage("No CarVolumeGroup in dump").that(volumeGroupProtoList) 2019 .isNotEmpty(); 2020 mVolumeGroupCount = volumeGroupProtoList.size(); 2021 mVolumeGroupId = volumeGroupProtoList.get(0).getId(); 2022 } 2023 } 2024 setVolumeGroupMute(int zoneId, int groupId, boolean mute)2025 private void setVolumeGroupMute(int zoneId, int groupId, boolean mute) { 2026 ShellUtils.runShellCommand("cmd car_service set-mute-car-volume-group %d %d %s", 2027 zoneId, groupId, mute ? "mute" : "unmute"); 2028 } 2029 assertVolumeGroupIdForUsages(int zoneId, int volumeGroupId, int[] usages, String message)2030 private void assertVolumeGroupIdForUsages(int zoneId, int volumeGroupId, int[] usages, 2031 String message) { 2032 assertWithMessage("Usage for volume group %s in zone %s %s", volumeGroupId, zoneId, 2033 message).that(usages).isNotEmpty(); 2034 for (int i = 0; i < usages.length; i++) { 2035 assertWithMessage("Usage %s in volume group %s in zone %s %s", usages[i], volumeGroupId, 2036 zoneId, message).that(mCarAudioManager.getVolumeGroupIdForUsage(zoneId, 2037 usages[i])).isEqualTo(volumeGroupId); 2038 } 2039 } 2040 2041 private static final class TestZoneConfigIdInfo { 2042 private final int mZoneId; 2043 private final int mConfigId; 2044 private final String mConfigName; 2045 TestZoneConfigIdInfo(int zoneId, int configId, String configName)2046 TestZoneConfigIdInfo(int zoneId, int configId, String configName) { 2047 mZoneId = zoneId; 2048 mConfigId = configId; 2049 mConfigName = configName; 2050 } 2051 2052 @Override equals(Object o)2053 public boolean equals(Object o) { 2054 if (this == o) { 2055 return true; 2056 } 2057 2058 if (!(o instanceof TestZoneConfigIdInfo)) { 2059 return false; 2060 } 2061 2062 TestZoneConfigIdInfo that = (TestZoneConfigIdInfo) o; 2063 2064 return mZoneId == that.mZoneId && mConfigId == that.mConfigId 2065 && mConfigName.equals(that.mConfigName); 2066 } 2067 getZoneConfigFromInfo(CarAudioZoneConfigInfo configInfo)2068 static TestZoneConfigIdInfo getZoneConfigFromInfo(CarAudioZoneConfigInfo configInfo) { 2069 return new TestZoneConfigIdInfo(configInfo.getZoneId(), configInfo.getConfigId(), 2070 configInfo.getName()); 2071 } 2072 getZoneConfigListFromInfoList( List<CarAudioZoneConfigInfo> configInfo)2073 static List<TestZoneConfigIdInfo> getZoneConfigListFromInfoList( 2074 List<CarAudioZoneConfigInfo> configInfo) { 2075 List<TestZoneConfigIdInfo> zoneConfigs = new ArrayList<>(configInfo.size()); 2076 Log.e(TAG, "getZoneConfigListFromInfoList " + configInfo.size()); 2077 for (int index = 0; index < configInfo.size(); index++) { 2078 zoneConfigs.add(getZoneConfigFromInfo(configInfo.get(index))); 2079 } 2080 return zoneConfigs; 2081 } 2082 } 2083 2084 private static final class TestPrimaryZoneMediaAudioRequestStatusCallback implements 2085 PrimaryZoneMediaAudioRequestCallback { 2086 2087 private final CountDownLatch mRequestAudioLatch = new CountDownLatch(1); 2088 private long mRequestId; 2089 private OccupantZoneInfo mOccupantZoneInfo; 2090 2091 @Override onRequestMediaOnPrimaryZone(OccupantZoneInfo info, long requestId)2092 public void onRequestMediaOnPrimaryZone(OccupantZoneInfo info, long requestId) { 2093 mOccupantZoneInfo = info; 2094 mRequestId = requestId; 2095 Log.i(TAG, "onRequestMediaOnPrimaryZone info " + info + " request id " + requestId); 2096 mRequestAudioLatch.countDown(); 2097 } 2098 2099 @Override onMediaAudioRequestStatusChanged(OccupantZoneInfo info, long requestId, int status)2100 public void onMediaAudioRequestStatusChanged(OccupantZoneInfo info, 2101 long requestId, int status) { 2102 } 2103 receivedMediaRequest()2104 void receivedMediaRequest() throws InterruptedException { 2105 await(mRequestAudioLatch, WAIT_TIMEOUT_MS); 2106 } 2107 } 2108 2109 private static final class TestMediaAudioRequestStatusCallback implements 2110 MediaAudioRequestStatusCallback { 2111 2112 private CountDownLatch mRequestAudioLatch = new CountDownLatch(1); 2113 private long mRequestId; 2114 private OccupantZoneInfo mOccupantZoneInfo; 2115 private int mStatus; 2116 receivedApproval()2117 void receivedApproval() throws InterruptedException { 2118 await(mRequestAudioLatch, WAIT_TIMEOUT_MS); 2119 } 2120 reset()2121 void reset() { 2122 mRequestAudioLatch = new CountDownLatch(1); 2123 mRequestId = INVALID_REQUEST_ID; 2124 mOccupantZoneInfo = null; 2125 mStatus = 0; 2126 } 2127 2128 @Override onMediaAudioRequestStatusChanged(OccupantZoneInfo info, long requestId, int status)2129 public void onMediaAudioRequestStatusChanged(OccupantZoneInfo info, 2130 long requestId, int status) { 2131 mOccupantZoneInfo = info; 2132 mRequestId = requestId; 2133 mStatus = status; 2134 Log.i(TAG, "onMediaAudioRequestStatusChanged info " + info + " request id " 2135 + requestId + " status " + status); 2136 mRequestAudioLatch.countDown(); 2137 } 2138 } 2139 2140 private static final class TestSwitchAudioZoneConfigCallback implements 2141 SwitchAudioZoneConfigCallback { 2142 2143 private CountDownLatch mRequestAudioLatch = new CountDownLatch(1); 2144 private CarAudioZoneConfigInfo mZoneConfigInfo; 2145 private boolean mIsSuccessful; 2146 receivedApproval()2147 void receivedApproval() throws InterruptedException { 2148 await(mRequestAudioLatch, WAIT_TIMEOUT_MS); 2149 } 2150 reset()2151 void reset() { 2152 mRequestAudioLatch = new CountDownLatch(1); 2153 mZoneConfigInfo = null; 2154 mIsSuccessful = false; 2155 } 2156 2157 @Override onAudioZoneConfigSwitched(CarAudioZoneConfigInfo zoneConfigInfo, boolean isSuccessful)2158 public void onAudioZoneConfigSwitched(CarAudioZoneConfigInfo zoneConfigInfo, 2159 boolean isSuccessful) { 2160 mZoneConfigInfo = zoneConfigInfo; 2161 mIsSuccessful = isSuccessful; 2162 Log.i(TAG, "onAudioZoneConfigSwitched zoneConfig " + zoneConfigInfo + " is successful? " 2163 + isSuccessful); 2164 mRequestAudioLatch.countDown(); 2165 } 2166 } 2167 2168 private static final class TestAudioZonesMirrorStatusCallback implements 2169 AudioZonesMirrorStatusCallback { 2170 2171 private CountDownLatch mRequestAudioLatch = new CountDownLatch(1); 2172 public List<Integer> mAudioZones; 2173 public int mStatus; 2174 2175 @Override onAudioZonesMirrorStatusChanged(List<Integer> mirroredAudioZones, int status)2176 public void onAudioZonesMirrorStatusChanged(List<Integer> mirroredAudioZones, int status) { 2177 mAudioZones = mirroredAudioZones; 2178 mStatus = status; 2179 Log.i(TAG, "onAudioZonesMirrorStatusChanged: audio zones " + mirroredAudioZones 2180 + " status " + status); 2181 mRequestAudioLatch.countDown(); 2182 } 2183 waitForCallback()2184 private void waitForCallback() throws InterruptedException { 2185 await(mRequestAudioLatch, WAIT_TIMEOUT_MS); 2186 } 2187 reset()2188 public void reset() { 2189 mRequestAudioLatch = new CountDownLatch(1); 2190 } 2191 } 2192 2193 } 2194