diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 031c057018ad7..754fa25191b07 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1253,6 +1253,7 @@ public class HdmiControlService extends SystemService { void setAudioStatus(boolean mute, int volume) { if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated() + || !tv().isArcEstablished() // Don't update TV volume when SAM is on and ARC is off || getHdmiCecVolumeControl() == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index 39e06a3a362d9..950b8a2540076 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -25,6 +25,13 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import android.content.Context; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; @@ -494,4 +501,99 @@ public class HdmiCecLocalDeviceTvTest { ABORT_UNRECOGNIZED_OPCODE); assertThat(mNativeWrapper.getResultMessages()).doesNotContain(featureAbort); } + + @Test + public void handleReportAudioStatus_SamOnArcOff_setStreamVolumeNotCalled() { + // Emulate Audio device on port 0x1000 (does not support ARC) + mNativeWrapper.setPortConnectionStatus(1, true); + HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(hdmiCecMessage); + + HdmiCecFeatureAction systemAudioAutoInitiationAction = + new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction); + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + + mTestLooper.dispatchAll(); + + // SAM must be on; ARC must be off + assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated()); + assertFalse(mHdmiCecLocalDeviceTv.isArcEstablished()); + + HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + 50, // Volume of incoming message does not affect HDMI-CEC logic + false); + mNativeWrapper.onCecMessage(reportAudioStatus); + + mTestLooper.dispatchAll(); + + verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); + } + + @Test + public void handleReportAudioStatus_SamOnArcOn_setStreamVolumeCalled() { + mNativeWrapper.setPortConnectionStatus(2, true); + HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(hdmiCecMessage); + + HdmiCecFeatureAction systemAudioAutoInitiationAction = + new SystemAudioAutoInitiationAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM); + mHdmiCecLocalDeviceTv.addAndStartAction(systemAudioAutoInitiationAction); + + HdmiCecMessage reportSystemAudioMode = HdmiCecMessageBuilder.buildReportSystemAudioMode( + ADDR_AUDIO_SYSTEM, mHdmiCecLocalDeviceTv.mAddress, true); + mHdmiControlService.handleCecCommand(reportSystemAudioMode); + + HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc( + ADDR_AUDIO_SYSTEM, + ADDR_TV); + mNativeWrapper.onCecMessage(requestArcInitiation); + + mTestLooper.dispatchAll(); + + // SAM and ARC must be on + assertTrue(mHdmiCecLocalDeviceTv.isSystemAudioActivated()); + assertTrue(mHdmiCecLocalDeviceTv.isArcEstablished()); + + HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + 50, // Volume of incoming message does not affect HDMI-CEC logic + false); + mNativeWrapper.onCecMessage(reportAudioStatus); + + mTestLooper.dispatchAll(); + + verify(mAudioManager, times(1)).setStreamVolume(anyInt(), anyInt(), anyInt()); + } + + @Test + public void handleReportAudioStatus_SamOff_setStreamVolumeNotCalled() { + // Emulate Audio device on port 0x1000 (does not support ARC) + mNativeWrapper.setPortConnectionStatus(1, true); + HdmiCecMessage hdmiCecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( + ADDR_AUDIO_SYSTEM, 0x1000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + mNativeWrapper.onCecMessage(hdmiCecMessage); + + mTestLooper.dispatchAll(); + + assertFalse(mHdmiCecLocalDeviceTv.isSystemAudioActivated()); + + HdmiCecMessage reportAudioStatus = HdmiCecMessageBuilder.buildReportAudioStatus( + ADDR_AUDIO_SYSTEM, + ADDR_TV, + 50, // Volume of incoming message does not affect HDMI-CEC logic + false); + mNativeWrapper.onCecMessage(reportAudioStatus); + + mTestLooper.dispatchAll(); + + verify(mAudioManager, never()).setStreamVolume(anyInt(), anyInt(), anyInt()); + } }