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 com.android.server.hdmi; 18 19 import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; 20 21 import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP; 22 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_BOOT_UP; 23 24 import static com.google.common.truth.Truth.assertThat; 25 import static com.google.common.truth.TruthJUnit.assume; 26 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyBoolean; 29 import static org.mockito.ArgumentMatchers.anyInt; 30 import static org.mockito.Mockito.clearInvocations; 31 import static org.mockito.Mockito.eq; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.spy; 34 import static org.mockito.Mockito.verify; 35 36 import android.content.Context; 37 import android.content.ContextWrapper; 38 import android.hardware.hdmi.DeviceFeatures; 39 import android.hardware.hdmi.HdmiControlManager; 40 import android.hardware.hdmi.HdmiDeviceInfo; 41 import android.hardware.hdmi.HdmiPortInfo; 42 import android.hardware.tv.cec.V1_0.SendMessageResult; 43 import android.media.AudioDeviceAttributes; 44 import android.media.AudioDeviceVolumeManager; 45 import android.media.AudioManager; 46 import android.media.VolumeInfo; 47 import android.os.Looper; 48 import android.os.RemoteException; 49 import android.os.test.TestLooper; 50 51 import androidx.test.InstrumentationRegistry; 52 53 import com.android.server.SystemService; 54 55 import org.junit.Before; 56 import org.junit.Test; 57 import org.mockito.MockitoAnnotations; 58 59 import java.util.ArrayList; 60 import java.util.Arrays; 61 import java.util.Collections; 62 63 /** 64 * Tests that absolute volume behavior (AVB) is enabled and disabled correctly, and that 65 * the device responds correctly to incoming <Report Audio Status> messages and API calls 66 * from AudioService when AVB is active. 67 * 68 * This is an abstract base class. Concrete subclasses specify the type of the local device, and the 69 * type of the System Audio device. This allows each test to be run for multiple setups. 70 * 71 * We test the following pairs of (local device, System Audio device): 72 * (Playback, TV): {@link PlaybackDeviceToTvAvbTest} 73 * (Playback, Audio System): {@link PlaybackDeviceToAudioSystemAvbTest} 74 * (TV, Audio System): {@link TvToAudioSystemAvbTest} 75 */ 76 public abstract class BaseAbsoluteVolumeBehaviorTest { 77 protected HdmiControlService mHdmiControlService; 78 private HdmiCecController mHdmiCecController; 79 private HdmiCecLocalDevice mHdmiCecLocalDevice; 80 private FakeHdmiCecConfig mHdmiCecConfig; 81 private FakePowerManagerWrapper mPowerManager; 82 private Looper mLooper; 83 private Context mContextSpy; 84 private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); 85 86 protected FakeAudioFramework mAudioFramework; 87 protected AudioManagerWrapper mAudioManager; 88 protected AudioDeviceVolumeManagerWrapper mAudioDeviceVolumeManager; 89 90 protected TestLooper mTestLooper = new TestLooper(); 91 protected FakeNativeWrapper mNativeWrapper; 92 93 // Default Audio Status given by the System Audio device in its initial <Report Audio Status> 94 // that triggers AVB being enabled 95 private static final AudioStatus INITIAL_SYSTEM_AUDIO_DEVICE_STATUS = 96 new AudioStatus(50, false); 97 98 // VolumeInfo passed to AudioDeviceVolumeManager#setDeviceAbsoluteVolumeBehavior to enable AVB 99 private static final VolumeInfo ENABLE_AVB_VOLUME_INFO = 100 new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 101 .setMuted(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()) 102 .setVolumeIndex(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume()) 103 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 104 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 105 .build(); 106 107 private static final int EMPTY_FLAGS = 0; 108 createLocalDevice(HdmiControlService hdmiControlService)109 protected abstract HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService); 110 getPhysicalAddress()111 protected abstract int getPhysicalAddress(); getDeviceType()112 protected abstract int getDeviceType(); getAudioOutputDevice()113 protected abstract AudioDeviceAttributes getAudioOutputDevice(); 114 getSystemAudioDeviceLogicalAddress()115 protected abstract int getSystemAudioDeviceLogicalAddress(); getSystemAudioDeviceType()116 protected abstract int getSystemAudioDeviceType(); 117 118 @Before setUp()119 public void setUp() throws RemoteException { 120 MockitoAnnotations.initMocks(this); 121 122 mContextSpy = spy(new ContextWrapper( 123 InstrumentationRegistry.getInstrumentation().getTargetContext())); 124 125 mAudioFramework = new FakeAudioFramework(); 126 mAudioManager = spy(mAudioFramework.getAudioManager()); 127 mAudioDeviceVolumeManager = spy(mAudioFramework.getAudioDeviceVolumeManager()); 128 129 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 1, EMPTY_FLAGS); 130 mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 131 132 mHdmiControlService = 133 new HdmiControlService(InstrumentationRegistry.getTargetContext(), 134 Collections.singletonList(getDeviceType()), 135 mAudioManager, mAudioDeviceVolumeManager) { 136 @Override 137 protected void writeStringSystemProperty(String key, String value) { 138 // do nothing 139 } 140 }; 141 142 mLooper = mTestLooper.getLooper(); 143 mHdmiControlService.setIoLooper(mLooper); 144 145 mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy); 146 mHdmiCecConfig.setIntValue( 147 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION, 148 HdmiControlManager.HDMI_CEC_VERSION_2_0); 149 mHdmiCecConfig.setIntValue( 150 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, 151 HdmiControlManager.VOLUME_CONTROL_DISABLED); 152 mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig); 153 mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper()); 154 155 mNativeWrapper = new FakeNativeWrapper(); 156 mNativeWrapper.setPhysicalAddress(getPhysicalAddress()); 157 mNativeWrapper.setPollAddressResponse(Constants.ADDR_TV, SendMessageResult.SUCCESS); 158 159 mHdmiCecController = HdmiCecController.createWithNativeWrapper( 160 mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); 161 mHdmiControlService.setCecController(mHdmiCecController); 162 mHdmiControlService.setHdmiMhlController( 163 HdmiMhlControllerStub.create(mHdmiControlService)); 164 mHdmiControlService.initService(); 165 mPowerManager = new FakePowerManagerWrapper(mContextSpy); 166 mHdmiControlService.setPowerManager(mPowerManager); 167 168 mHdmiCecLocalDevice = createLocalDevice(mHdmiControlService); 169 mHdmiCecLocalDevice.init(); 170 mLocalDevices.add(mHdmiCecLocalDevice); 171 172 HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1]; 173 hdmiPortInfos[0] = 174 new HdmiPortInfo.Builder(1, HdmiPortInfo.PORT_OUTPUT, 0x0000) 175 .setCecSupported(true) 176 .setMhlSupported(false) 177 .setArcSupported(false) 178 .build(); 179 mNativeWrapper.setPortInfo(hdmiPortInfos); 180 mNativeWrapper.setPortConnectionStatus(1, true); 181 182 mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_BOOT_UP); 183 mTestLooper.dispatchAll(); 184 185 // Audio service always plays STREAM_MUSIC on the device we need 186 mAudioFramework.setDevicesForAttributes(HdmiControlService.STREAM_MUSIC_ATTRIBUTES, 187 Collections.singletonList(getAudioOutputDevice())); 188 189 // Max volume of STREAM_MUSIC 190 mAudioFramework.setStreamMaxVolume(AudioManager.STREAM_MUSIC, 25); 191 192 // Receive messages from devices to make sure they're registered in HdmiCecNetwork 193 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus( 194 Constants.ADDR_TV, getLogicalAddress())); 195 if (getSystemAudioDeviceType() == DEVICE_AUDIO_SYSTEM) { 196 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveDevicePowerStatus( 197 Constants.ADDR_AUDIO_SYSTEM, getLogicalAddress())); 198 } 199 200 mHdmiControlService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); 201 mHdmiControlService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 202 mTestLooper.dispatchAll(); 203 } 204 getLogicalAddress()205 protected int getLogicalAddress() { 206 return mHdmiCecLocalDevice.getDeviceInfo().getLogicalAddress(); 207 } 208 209 /** 210 * Changes the setting for CEC volume. 211 */ setCecVolumeControlSetting(@dmiControlManager.VolumeControl int setting)212 protected void setCecVolumeControlSetting(@HdmiControlManager.VolumeControl int setting) { 213 mHdmiControlService.getHdmiCecConfig().setIntValue( 214 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, setting); 215 mTestLooper.dispatchAll(); 216 } 217 218 /** 219 * Has the device receive a <Report Features> message from the System Audio device specifying 220 * whether <Set Audio Volume Level> is supported or not. 221 */ receiveSetAudioVolumeLevelSupport( @eviceFeatures.FeatureSupportStatus int featureSupportStatus)222 protected void receiveSetAudioVolumeLevelSupport( 223 @DeviceFeatures.FeatureSupportStatus int featureSupportStatus) { 224 // <Report Features> can't specify an unknown feature support status 225 if (featureSupportStatus != DeviceFeatures.FEATURE_SUPPORT_UNKNOWN) { 226 mNativeWrapper.onCecMessage(ReportFeaturesMessage.build( 227 getSystemAudioDeviceLogicalAddress(), HdmiControlManager.HDMI_CEC_VERSION_2_0, 228 Arrays.asList(getSystemAudioDeviceType()), Constants.RC_PROFILE_SOURCE, 229 Collections.emptyList(), 230 DeviceFeatures.NO_FEATURES_SUPPORTED.toBuilder() 231 .setSetAudioVolumeLevelSupport(featureSupportStatus) 232 .build())); 233 mTestLooper.dispatchAll(); 234 } 235 } 236 237 /** 238 * Enables System Audio mode if the System Audio device is an Audio System. 239 */ enableSystemAudioModeIfNeeded()240 protected void enableSystemAudioModeIfNeeded() { 241 if (getSystemAudioDeviceType() == DEVICE_AUDIO_SYSTEM) { 242 receiveSetSystemAudioMode(true); 243 } 244 } 245 246 /** 247 * Sets System Audio Mode by having the device receive <Set System Audio Mode> 248 * from the Audio System. 249 */ receiveSetSystemAudioMode(boolean status)250 protected void receiveSetSystemAudioMode(boolean status) { 251 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildSetSystemAudioMode( 252 Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_BROADCAST, status)); 253 mTestLooper.dispatchAll(); 254 } 255 256 /** 257 * Has the device receive a <Report Audio Status> message from the System Audio Device. 258 */ receiveReportAudioStatus(int volume, boolean mute)259 protected void receiveReportAudioStatus(int volume, boolean mute) { 260 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportAudioStatus( 261 getSystemAudioDeviceLogicalAddress(), 262 getLogicalAddress(), 263 volume, 264 mute)); 265 mTestLooper.dispatchAll(); 266 } 267 268 /** 269 * Triggers all the conditions required to enable absolute volume behavior. 270 */ enableAbsoluteVolumeBehavior()271 protected void enableAbsoluteVolumeBehavior() { 272 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 273 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 274 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 275 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 276 enableSystemAudioModeIfNeeded(); 277 receiveReportAudioStatus( 278 INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(), 279 INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()); 280 281 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 282 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); 283 } 284 enableAdjustOnlyAbsoluteVolumeBehavior()285 protected void enableAdjustOnlyAbsoluteVolumeBehavior() { 286 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 287 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 288 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 289 enableSystemAudioModeIfNeeded(); 290 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); 291 receiveReportAudioStatus( 292 INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume(), 293 INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()); 294 295 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 296 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); 297 } 298 verifyGiveAudioStatusNeverSent()299 protected void verifyGiveAudioStatusNeverSent() { 300 assertThat(mNativeWrapper.getResultMessages()).doesNotContain( 301 HdmiCecMessageBuilder.buildGiveAudioStatus( 302 getLogicalAddress(), getSystemAudioDeviceLogicalAddress())); 303 } 304 verifyGiveAudioStatusSent()305 protected void verifyGiveAudioStatusSent() { 306 assertThat(mNativeWrapper.getResultMessages()).contains( 307 HdmiCecMessageBuilder.buildGiveAudioStatus( 308 getLogicalAddress(), getSystemAudioDeviceLogicalAddress())); 309 } 310 311 @Test allConditionsExceptSavlSupportMet_sendsSetAudioVolumeLevelAndGiveFeatures()312 public void allConditionsExceptSavlSupportMet_sendsSetAudioVolumeLevelAndGiveFeatures() { 313 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 314 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 315 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 316 enableSystemAudioModeIfNeeded(); 317 318 assertThat(mNativeWrapper.getResultMessages()).contains( 319 SetAudioVolumeLevelMessage.build( 320 getLogicalAddress(), getSystemAudioDeviceLogicalAddress(), 321 Constants.AUDIO_VOLUME_STATUS_UNKNOWN)); 322 assertThat(mNativeWrapper.getResultMessages()).contains( 323 HdmiCecMessageBuilder.buildGiveFeatures( 324 getLogicalAddress(), getSystemAudioDeviceLogicalAddress())); 325 } 326 327 @Test allConditionsMet_savlSupportLast_reportFeatures_giveAudioStatusSent()328 public void allConditionsMet_savlSupportLast_reportFeatures_giveAudioStatusSent() { 329 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 330 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 331 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 332 enableSystemAudioModeIfNeeded(); 333 verifyGiveAudioStatusNeverSent(); 334 335 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 336 verifyGiveAudioStatusSent(); 337 } 338 339 @Test allConditionsMet_savlSupportLast_noFeatureAbort_giveAudioStatusSent()340 public void allConditionsMet_savlSupportLast_noFeatureAbort_giveAudioStatusSent() { 341 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 342 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 343 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 344 enableSystemAudioModeIfNeeded(); 345 verifyGiveAudioStatusNeverSent(); 346 347 mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); 348 mTestLooper.dispatchAll(); 349 verifyGiveAudioStatusSent(); 350 } 351 352 @Test allConditionsMet_cecVolumeEnabledLast_giveAudioStatusSent()353 public void allConditionsMet_cecVolumeEnabledLast_giveAudioStatusSent() { 354 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 355 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 356 enableSystemAudioModeIfNeeded(); 357 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 358 verifyGiveAudioStatusNeverSent(); 359 360 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 361 verifyGiveAudioStatusSent(); 362 } 363 364 @Test allConditionsMet_fullVolumeBehaviorLast_giveAudioStatusSent()365 public void allConditionsMet_fullVolumeBehaviorLast_giveAudioStatusSent() { 366 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 367 enableSystemAudioModeIfNeeded(); 368 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 369 verifyGiveAudioStatusNeverSent(); 370 371 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 372 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 373 mTestLooper.dispatchAll(); 374 verifyGiveAudioStatusSent(); 375 } 376 377 @Test allConditionsMet_systemAudioModeEnabledLast_giveAudioStatusSent()378 public void allConditionsMet_systemAudioModeEnabledLast_giveAudioStatusSent() { 379 // Only run when the System Audio device is an Audio System. 380 assume().that(getSystemAudioDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); 381 382 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 383 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 384 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 385 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 386 verifyGiveAudioStatusNeverSent(); 387 388 receiveSetSystemAudioMode(true); 389 verifyGiveAudioStatusSent(); 390 } 391 392 @Test giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avbEnabled()393 public void giveAudioStatusSent_systemAudioDeviceSendsReportAudioStatus_avbEnabled() { 394 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 395 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 396 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 397 enableSystemAudioModeIfNeeded(); 398 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 399 400 // AVB should not be enabled before receiving <Report Audio Status> 401 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 402 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 403 404 receiveReportAudioStatus(60, false); 405 406 // Check that absolute volume behavior was the last one adopted 407 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 408 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); 409 410 // Check that the volume and mute status received were included when setting AVB 411 verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeBehavior( 412 eq(getAudioOutputDevice()), 413 eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 414 .setVolumeIndex(60) 415 .setMuted(false) 416 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 417 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 418 .build()), 419 any(), any(), anyBoolean()); 420 } 421 422 @Test giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avbNotEnabled()423 public void giveAudioStatusSent_reportAudioStatusVolumeOutOfBounds_avbNotEnabled() { 424 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 425 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 426 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 427 enableSystemAudioModeIfNeeded(); 428 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_SUPPORTED); 429 430 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 431 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 432 receiveReportAudioStatus(127, false); 433 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 434 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 435 } 436 437 @Test avbEnabled_cecVolumeDisabled_avbDisabled()438 public void avbEnabled_cecVolumeDisabled_avbDisabled() { 439 enableAbsoluteVolumeBehavior(); 440 441 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_DISABLED); 442 443 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 444 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 445 } 446 447 @Test avbEnabled_setAudioVolumeLevelNotSupported_avbDisabled()448 public void avbEnabled_setAudioVolumeLevelNotSupported_avbDisabled() { 449 enableAbsoluteVolumeBehavior(); 450 451 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); 452 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 453 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 454 } 455 456 @Test avbEnabled_setAudioVolumeLevelFeatureAborted_avbDisabled()457 public void avbEnabled_setAudioVolumeLevelFeatureAborted_avbDisabled() { 458 enableAbsoluteVolumeBehavior(); 459 460 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 461 getSystemAudioDeviceLogicalAddress(), getLogicalAddress(), 462 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_UNRECOGNIZED_OPCODE)); 463 mTestLooper.dispatchAll(); 464 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 465 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 466 } 467 468 @Test avbEnabled_systemAudioModeDisabled_avbDisabled()469 public void avbEnabled_systemAudioModeDisabled_avbDisabled() { 470 // Only run when the System Audio device is an Audio System. 471 assume().that(getSystemAudioDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); 472 473 enableAbsoluteVolumeBehavior(); 474 475 receiveSetSystemAudioMode(false); 476 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 477 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 478 } 479 480 @Test avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges()481 public void avbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { 482 // Initial <Report Audio Status> has volume=50 and mute=false 483 enableAbsoluteVolumeBehavior(); 484 485 // New volume and mute status: sets both 486 receiveReportAudioStatus(20, true); 487 verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(5), 488 anyInt()); 489 verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 490 eq(AudioManager.ADJUST_MUTE), anyInt()); 491 clearInvocations(mAudioManager); 492 493 // New volume only: sets volume only 494 receiveReportAudioStatus(32, true); 495 verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 496 anyInt()); 497 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 498 eq(AudioManager.ADJUST_MUTE), anyInt()); 499 clearInvocations(mAudioManager); 500 501 // New mute status only: sets mute only 502 receiveReportAudioStatus(32, false); 503 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 504 anyInt()); 505 verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 506 eq(AudioManager.ADJUST_UNMUTE), anyInt()); 507 clearInvocations(mAudioManager); 508 509 // Repeat of earlier message: sets neither volume nor mute 510 receiveReportAudioStatus(32, false); 511 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 512 anyInt()); 513 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 514 eq(AudioManager.ADJUST_UNMUTE), anyInt()); 515 clearInvocations(mAudioManager); 516 517 // Volume not within range [0, 100]: sets neither volume nor mute 518 receiveReportAudioStatus(127, true); 519 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), 520 anyInt()); 521 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), 522 anyInt()); 523 clearInvocations(mAudioManager); 524 525 // If AudioService causes us to send <Set Audio Volume Level>, the System Audio device's 526 // volume changes. Afterward, a duplicate of an earlier <Report Audio Status> should 527 // still cause us to call setStreamVolume() 528 mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( 529 getAudioOutputDevice(), 530 new VolumeInfo.Builder(ENABLE_AVB_VOLUME_INFO) 531 .setVolumeIndex(20) 532 .build() 533 ); 534 mTestLooper.dispatchAll(); 535 receiveReportAudioStatus(32, false); 536 verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 537 anyInt()); 538 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 539 eq(AudioManager.ADJUST_UNMUTE), anyInt()); 540 } 541 542 @Test avbEnabled_audioDeviceVolumeAdjusted_sendsUserControlPressedAndGiveAudioStatus()543 public void avbEnabled_audioDeviceVolumeAdjusted_sendsUserControlPressedAndGiveAudioStatus() { 544 enableAbsoluteVolumeBehavior(); 545 mNativeWrapper.clearResultMessages(); 546 547 mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted( 548 getAudioOutputDevice(), 549 ENABLE_AVB_VOLUME_INFO, 550 AudioManager.ADJUST_RAISE, 551 AudioDeviceVolumeManager.ADJUST_MODE_NORMAL 552 ); 553 mTestLooper.dispatchAll(); 554 555 assertThat(mNativeWrapper.getResultMessages()).contains( 556 HdmiCecMessageBuilder.buildUserControlPressed(getLogicalAddress(), 557 getSystemAudioDeviceLogicalAddress(), CEC_KEYCODE_VOLUME_UP)); 558 assertThat(mNativeWrapper.getResultMessages()).contains( 559 HdmiCecMessageBuilder.buildUserControlReleased(getLogicalAddress(), 560 getSystemAudioDeviceLogicalAddress())); 561 assertThat(mNativeWrapper.getResultMessages()).contains( 562 HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(), 563 getSystemAudioDeviceLogicalAddress())); 564 } 565 566 @Test avbEnabled_audioDeviceVolumeChanged_sendsSetAudioVolumeLevel()567 public void avbEnabled_audioDeviceVolumeChanged_sendsSetAudioVolumeLevel() { 568 enableAbsoluteVolumeBehavior(); 569 mNativeWrapper.clearResultMessages(); 570 571 mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( 572 getAudioOutputDevice(), 573 new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 574 .setVolumeIndex(20) 575 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 576 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 577 .build() 578 ); 579 mTestLooper.dispatchAll(); 580 581 assertThat(mNativeWrapper.getResultMessages()).contains( 582 SetAudioVolumeLevelMessage.build(getLogicalAddress(), 583 getSystemAudioDeviceLogicalAddress(), 20)); 584 } 585 } 586