From 17c51c7b85344647d05030615bb501cefb72c10e Mon Sep 17 00:00:00 2001 From: Marvin Ramin Date: Mon, 7 Dec 2020 16:41:19 +0100 Subject: [PATCH] Track CEC version of CEC devices Update tracked devices CEC version based on messages received by remote devices. Messages that can indicate CEC version are: , , (broadcast). Bug: 169121287 Test: atest HdmiCecNetworkTest Change-Id: I944dc1cdb93b32fb28fef4b2c111a08b232543c4 --- .../server/hdmi/HdmiCecLocalDevice.java | 10 ++ .../android/server/hdmi/HdmiCecNetwork.java | 49 ++++++++- .../server/hdmi/HdmiCecLocalDeviceTest.java | 12 +++ .../server/hdmi/HdmiCecNetworkTest.java | 100 +++++++++++++++++- 4 files changed, 167 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 9b3f788d7457e..0e196f278ddf9 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -282,6 +282,8 @@ abstract class HdmiCecLocalDevice { return handleGiveOsdName(message); case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID: return handleGiveDeviceVendorId(null); + case Constants.MESSAGE_CEC_VERSION: + return handleCecVersion(); case Constants.MESSAGE_GET_CEC_VERSION: return handleGetCecVersion(message); case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: @@ -405,6 +407,14 @@ abstract class HdmiCecLocalDevice { return true; } + @ServiceThreadOnly + private boolean handleCecVersion() { + assertRunOnServiceThread(); + + // Return true to avoid responses. Cec Version is tracked in HdmiCecNetwork. + return true; + } + @ServiceThreadOnly protected boolean handleActiveSource(HdmiCecMessage message) { return false; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index f032bfd2e929d..b748ae026cfc9 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -166,7 +166,6 @@ public class HdmiCecNetwork { } return false; } - /** * Clear all logical addresses registered in the device. * @@ -523,10 +522,31 @@ public class HdmiCecNetwork { case Constants.MESSAGE_DEVICE_VENDOR_ID: handleDeviceVendorId(message); break; - + case Constants.MESSAGE_CEC_VERSION: + handleCecVersion(message); + break; + case Constants.MESSAGE_REPORT_FEATURES: + handleReportFeatures(message); + break; } } + @ServiceThreadOnly + private void handleReportFeatures(HdmiCecMessage message) { + assertRunOnServiceThread(); + + int version = Byte.toUnsignedInt(message.getParams()[0]); + updateDeviceCecVersion(message.getSource(), version); + } + + @ServiceThreadOnly + private void handleCecVersion(HdmiCecMessage message) { + assertRunOnServiceThread(); + + int version = Byte.toUnsignedInt(message.getParams()[0]); + updateDeviceCecVersion(message.getSource(), version); + } + @ServiceThreadOnly private void handleReportPhysicalAddress(HdmiCecMessage message) { assertRunOnServiceThread(); @@ -555,6 +575,31 @@ public class HdmiCecNetwork { // Update power status of device int newStatus = message.getParams()[0] & 0xFF; updateDevicePowerStatus(message.getSource(), newStatus); + + if (message.getDestination() == Constants.ADDR_BROADCAST) { + updateDeviceCecVersion(message.getSource(), HdmiControlManager.HDMI_CEC_VERSION_2_0); + } + } + + @ServiceThreadOnly + private void updateDeviceCecVersion(int logicalAddress, int hdmiCecVersion) { + assertRunOnServiceThread(); + HdmiDeviceInfo deviceInfo = getCecDeviceInfo(logicalAddress); + if (deviceInfo == null) { + Slog.w(TAG, "Can not update CEC version of non-existing device:" + logicalAddress); + return; + } + + if (deviceInfo.getCecVersion() == hdmiCecVersion) { + return; + } + + HdmiDeviceInfo updatedDeviceInfo = new HdmiDeviceInfo(deviceInfo.getLogicalAddress(), + deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(), deviceInfo.getDeviceType(), + deviceInfo.getVendorId(), + deviceInfo.getDisplayName(), deviceInfo.getDevicePowerStatus(), + hdmiCecVersion); + updateCecDevice(updatedDeviceInfo); } @ServiceThreadOnly diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java index 2f49fb79c3dc9..2cb1113e7325d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -25,6 +25,8 @@ import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID; import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -264,4 +266,14 @@ public class HdmiCecLocalDeviceTest { assertFalse(result); } + + @Test + public void handleCecVersion_isHandled() { + boolean result = mHdmiLocalDevice.onMessage( + HdmiCecMessageBuilder.buildCecVersion(ADDR_PLAYBACK_1, mHdmiLocalDevice.mAddress, + HdmiControlManager.HDMI_CEC_VERSION_1_4_b)); + + assertThat(result).isTrue(); + } + } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java index 080b52bbbc6ad..e370018053986 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecNetworkTest.java @@ -36,6 +36,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -313,6 +314,7 @@ public class HdmiCecNetworkTest { int powerStatus = HdmiControlManager.POWER_STATUS_ON; String osdName = "Test Device"; int vendorId = 1234; + int cecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; mHdmiCecNetwork.handleCecMessage( HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(logicalAddress, @@ -325,6 +327,8 @@ public class HdmiCecNetworkTest { Constants.ADDR_BROADCAST, osdName)); mHdmiCecNetwork.handleCecMessage( HdmiCecMessageBuilder.buildDeviceVendorIdCommand(logicalAddress, vendorId)); + mHdmiCecNetwork.handleCecMessage(HdmiCecMessageBuilder.buildCecVersion(logicalAddress, + Constants.ADDR_BROADCAST, cecVersion)); assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); @@ -335,6 +339,7 @@ public class HdmiCecNetworkTest { assertThat(cecDeviceInfo.getDisplayName()).isEqualTo(osdName); assertThat(cecDeviceInfo.getVendorId()).isEqualTo(vendorId); assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(powerStatus); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion); } @Test @@ -374,16 +379,18 @@ public class HdmiCecNetworkTest { mHdmiCecNetwork.handleCecMessage( HdmiCecMessageBuilder.buildReportPowerStatus(logicalAddress, - Constants.ADDR_BROADCAST, powerStatus)); + Constants.ADDR_TV, powerStatus)); mHdmiCecNetwork.handleCecMessage( HdmiCecMessageBuilder.buildReportPowerStatus(logicalAddress, - Constants.ADDR_BROADCAST, updatedPowerStatus)); + Constants.ADDR_TV, updatedPowerStatus)); assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(updatedPowerStatus); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo( + HdmiControlManager.HDMI_CEC_VERSION_1_4_b); } @Test @@ -428,6 +435,8 @@ public class HdmiCecNetworkTest { assertThat(cecDeviceInfo.getVendorId()).isEqualTo(updatedVendorId); assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo( HdmiControlManager.POWER_STATUS_UNKNOWN); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo( + HdmiControlManager.HDMI_CEC_VERSION_1_4_b); } @Test @@ -446,4 +455,91 @@ public class HdmiCecNetworkTest { HdmiControlManager.DEVICE_EVENT_ADD_DEVICE, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); } + + @Test + public void cecDevices_tracking_reportPowerStatus_broadcast_infersCec2() { + int logicalAddress = Constants.ADDR_PLAYBACK_1; + int powerStatus = HdmiControlManager.POWER_STATUS_ON; + mHdmiCecNetwork.handleCecMessage( + HdmiCecMessageBuilder.buildReportPowerStatus(logicalAddress, + Constants.ADDR_BROADCAST, powerStatus)); + + assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); + + HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); + assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); + assertThat(cecDeviceInfo.getPhysicalAddress()).isEqualTo( + Constants.INVALID_PHYSICAL_ADDRESS); + assertThat(cecDeviceInfo.getDeviceType()).isEqualTo(HdmiDeviceInfo.DEVICE_RESERVED); + assertThat(cecDeviceInfo.getVendorId()).isEqualTo(Constants.UNKNOWN_VENDOR_ID); + assertThat(cecDeviceInfo.getDisplayName()).isEqualTo( + HdmiUtils.getDefaultDeviceName(logicalAddress)); + assertThat(cecDeviceInfo.getDevicePowerStatus()).isEqualTo(powerStatus); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo( + HdmiControlManager.HDMI_CEC_VERSION_2_0); + } + + @Test + public void cecDevices_tracking_reportCecVersion_tracksCecVersion_cec14() { + int logicalAddress = Constants.ADDR_PLAYBACK_1; + int cecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_b; + mHdmiCecNetwork.handleCecMessage( + HdmiCecMessageBuilder.buildCecVersion(logicalAddress, Constants.ADDR_BROADCAST, + cecVersion)); + + assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); + + HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); + assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion); + } + + @Test + public void cecDevices_tracking_reportCecVersion_tracksCecVersion_cec20() { + int logicalAddress = Constants.ADDR_PLAYBACK_1; + int cecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; + mHdmiCecNetwork.handleCecMessage( + HdmiCecMessageBuilder.buildCecVersion(logicalAddress, Constants.ADDR_BROADCAST, + cecVersion)); + + assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); + + HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); + assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion); + } + + @Test + public void cecDevices_tracking_reportFeatures_tracksCecVersion_cec14() { + int logicalAddress = Constants.ADDR_PLAYBACK_1; + int cecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_b; + mHdmiCecNetwork.handleCecMessage( + HdmiCecMessageBuilder.buildReportFeatures(logicalAddress, + cecVersion, Collections.emptyList(), + Constants.RC_PROFILE_SOURCE, Collections.emptyList(), + Collections.emptyList())); + + assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); + + HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); + assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion); + } + + @Test + public void cecDevices_tracking_reportFeatures_tracksCecVersion_cec20() { + int logicalAddress = Constants.ADDR_PLAYBACK_1; + int cecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; + mHdmiCecNetwork.handleCecMessage( + HdmiCecMessageBuilder.buildReportFeatures(logicalAddress, + cecVersion, Collections.emptyList(), + Constants.RC_PROFILE_SOURCE, Collections.emptyList(), + Collections.emptyList())); + + assertThat(mHdmiCecNetwork.getSafeCecDevicesLocked()).hasSize(1); + + HdmiDeviceInfo cecDeviceInfo = mHdmiCecNetwork.getCecDeviceInfo(logicalAddress); + assertThat(cecDeviceInfo.getLogicalAddress()).isEqualTo(logicalAddress); + assertThat(cecDeviceInfo.getCecVersion()).isEqualTo(cecVersion); + } }