From ada37c46910d459a5e3f7db9e74a87ec98062060 Mon Sep 17 00:00:00 2001 From: Marvin Ramin Date: Wed, 16 Jun 2021 10:22:42 +0200 Subject: [PATCH] Fix missing invocation of HdmiControlStatusListener HdmiControlStatusListener is invoked with incorrect values and not updated when DevicePowerStatusAction returns a result. This has an effect of listeners receiving incorrect values. In addition this impacts volume control behaviors via CEC. Bug: 191224732 Test: manual + atest Change-Id: Ied18ea0c52988851f5caae824c448a0c932600cb --- .../server/hdmi/HdmiControlService.java | 13 ++- .../server/hdmi/HdmiControlServiceTest.java | 95 +++++++++++++++++++ 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 2ed160a33af4c..a086bdaa6ec9f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -2580,7 +2580,8 @@ public class HdmiControlService extends SystemService { return null; } - private void addHdmiControlStatusChangeListener( + @VisibleForTesting + void addHdmiControlStatusChangeListener( final IHdmiControlStatusChangeListener listener) { final HdmiControlStatusChangeListenerRecord record = new HdmiControlStatusChangeListenerRecord(listener); @@ -2916,13 +2917,17 @@ public class HdmiControlService extends SystemService { } else { mIsCecAvailable = true; } + if (!listeners.isEmpty()) { + invokeHdmiControlStatusChangeListenerLocked(listeners, + isEnabled, mIsCecAvailable); + } } }); } else { mIsCecAvailable = false; - } - if (!listeners.isEmpty()) { - invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, mIsCecAvailable); + if (!listeners.isEmpty()) { + invokeHdmiControlStatusChangeListenerLocked(listeners, isEnabled, mIsCecAvailable); + } } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 0cf212c20c1ec..f53ae525eabab 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -40,6 +40,7 @@ import android.content.ContextWrapper; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener; +import android.hardware.hdmi.IHdmiControlStatusChangeListener; import android.os.Binder; import android.os.IPowerManager; import android.os.IThermalService; @@ -683,6 +684,100 @@ public class HdmiControlServiceTest { HdmiControlManager.HDMI_CEC_VERSION_2_0); } + @Test + public void initCec_statusListener_CecDisabled() { + HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback(); + + mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback); + + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + + assertThat(hdmiControlStatusCallback.mCecEnabled).isFalse(); + assertThat(hdmiControlStatusCallback.mCecAvailable).isFalse(); + } + + @Test + public void initCec_statusListener_CecEnabled_NoCecResponse() { + HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback(); + + mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback); + + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, + HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mTestLooper.dispatchAll(); + // Hit timeout twice due to retries + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); + mTestLooper.dispatchAll(); + + assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue(); + assertThat(hdmiControlStatusCallback.mCecAvailable).isFalse(); + } + + @Test + public void initCec_statusListener_CecEnabled_CecAvailable_TvOn() { + HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback(); + mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + + mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback); + mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, + mHdmiControlServiceSpy.playback().mAddress, HdmiControlManager.POWER_STATUS_ON); + mNativeWrapper.onCecMessage(reportPowerStatus); + mTestLooper.dispatchAll(); + + assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue(); + assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue(); + } + + @Test + public void initCec_statusListener_CecEnabled_CecAvailable_TvStandby() { + HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback(); + mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED); + mTestLooper.dispatchAll(); + + mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback); + mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED); + mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus( + Constants.ADDR_TV, + mHdmiControlServiceSpy.playback().mAddress, + HdmiControlManager.POWER_STATUS_STANDBY); + mNativeWrapper.onCecMessage(reportPowerStatus); + mTestLooper.dispatchAll(); + + assertThat(hdmiControlStatusCallback.mCecEnabled).isTrue(); + assertThat(hdmiControlStatusCallback.mCecAvailable).isTrue(); + } + + private static class HdmiControlStatusCallback extends IHdmiControlStatusChangeListener.Stub { + boolean mCecEnabled = false; + boolean mCecAvailable = false; + + @Override + public void onStatusChange(int isCecEnabled, boolean isCecAvailable) + throws RemoteException { + mCecEnabled = isCecEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED; + mCecAvailable = isCecAvailable; + } + } + private static class VolumeControlFeatureCallback extends IHdmiCecVolumeControlFeatureListener.Stub { boolean mCallbackReceived = false;