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