diff options
13 files changed, 449 insertions, 74 deletions
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index 5fddae53d632..d0cc8e71dbfa 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -88,79 +88,84 @@ final class Constants { @Retention(RetentionPolicy.SOURCE) @IntDef({ - MESSAGE_FEATURE_ABORT, - MESSAGE_IMAGE_VIEW_ON, - MESSAGE_TUNER_STEP_INCREMENT, - MESSAGE_TUNER_STEP_DECREMENT, - MESSAGE_TUNER_DEVICE_STATUS, - MESSAGE_GIVE_TUNER_DEVICE_STATUS, - MESSAGE_RECORD_ON, - MESSAGE_RECORD_STATUS, - MESSAGE_RECORD_OFF, - MESSAGE_TEXT_VIEW_ON, - MESSAGE_RECORD_TV_SCREEN, - MESSAGE_GIVE_DECK_STATUS, - MESSAGE_DECK_STATUS, - MESSAGE_SET_MENU_LANGUAGE, - MESSAGE_CLEAR_ANALOG_TIMER, - MESSAGE_SET_ANALOG_TIMER, - MESSAGE_TIMER_STATUS, - MESSAGE_STANDBY, - MESSAGE_PLAY, - MESSAGE_DECK_CONTROL, - MESSAGE_TIMER_CLEARED_STATUS, - MESSAGE_USER_CONTROL_PRESSED, - MESSAGE_USER_CONTROL_RELEASED, - MESSAGE_GIVE_OSD_NAME, - MESSAGE_SET_OSD_NAME, - MESSAGE_SET_OSD_STRING, - MESSAGE_SET_TIMER_PROGRAM_TITLE, - MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, - MESSAGE_GIVE_AUDIO_STATUS, - MESSAGE_SET_SYSTEM_AUDIO_MODE, - MESSAGE_REPORT_AUDIO_STATUS, - MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, - MESSAGE_SYSTEM_AUDIO_MODE_STATUS, - MESSAGE_ROUTING_CHANGE, - MESSAGE_ROUTING_INFORMATION, - MESSAGE_ACTIVE_SOURCE, - MESSAGE_GIVE_PHYSICAL_ADDRESS, - MESSAGE_REPORT_PHYSICAL_ADDRESS, - MESSAGE_REQUEST_ACTIVE_SOURCE, - MESSAGE_SET_STREAM_PATH, - MESSAGE_DEVICE_VENDOR_ID, - MESSAGE_VENDOR_COMMAND, - MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, - MESSAGE_VENDOR_REMOTE_BUTTON_UP, - MESSAGE_GIVE_DEVICE_VENDOR_ID, - MESSAGE_MENU_REQUEST, - MESSAGE_MENU_STATUS, - MESSAGE_GIVE_DEVICE_POWER_STATUS, - MESSAGE_REPORT_POWER_STATUS, - MESSAGE_GET_MENU_LANGUAGE, - MESSAGE_SELECT_ANALOG_SERVICE, - MESSAGE_SELECT_DIGITAL_SERVICE, - MESSAGE_SET_DIGITAL_TIMER, - MESSAGE_CLEAR_DIGITAL_TIMER, - MESSAGE_SET_AUDIO_RATE, - MESSAGE_INACTIVE_SOURCE, - MESSAGE_CEC_VERSION, - MESSAGE_GET_CEC_VERSION, - MESSAGE_VENDOR_COMMAND_WITH_ID, - MESSAGE_CLEAR_EXTERNAL_TIMER, - MESSAGE_SET_EXTERNAL_TIMER, - MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, - MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, - MESSAGE_INITIATE_ARC, - MESSAGE_REPORT_ARC_INITIATED, - MESSAGE_REPORT_ARC_TERMINATED, - MESSAGE_REQUEST_ARC_INITIATION, - MESSAGE_REQUEST_ARC_TERMINATION, - MESSAGE_TERMINATE_ARC, - MESSAGE_CDC_MESSAGE, - MESSAGE_ABORT, + MESSAGE_FEATURE_ABORT, + MESSAGE_IMAGE_VIEW_ON, + MESSAGE_TUNER_STEP_INCREMENT, + MESSAGE_TUNER_STEP_DECREMENT, + MESSAGE_TUNER_DEVICE_STATUS, + MESSAGE_GIVE_TUNER_DEVICE_STATUS, + MESSAGE_RECORD_ON, + MESSAGE_RECORD_STATUS, + MESSAGE_RECORD_OFF, + MESSAGE_TEXT_VIEW_ON, + MESSAGE_RECORD_TV_SCREEN, + MESSAGE_GIVE_DECK_STATUS, + MESSAGE_DECK_STATUS, + MESSAGE_SET_MENU_LANGUAGE, + MESSAGE_CLEAR_ANALOG_TIMER, + MESSAGE_SET_ANALOG_TIMER, + MESSAGE_TIMER_STATUS, + MESSAGE_STANDBY, + MESSAGE_PLAY, + MESSAGE_DECK_CONTROL, + MESSAGE_TIMER_CLEARED_STATUS, + MESSAGE_USER_CONTROL_PRESSED, + MESSAGE_USER_CONTROL_RELEASED, + MESSAGE_GIVE_OSD_NAME, + MESSAGE_SET_OSD_NAME, + MESSAGE_SET_OSD_STRING, + MESSAGE_SET_TIMER_PROGRAM_TITLE, + MESSAGE_SYSTEM_AUDIO_MODE_REQUEST, + MESSAGE_GIVE_AUDIO_STATUS, + MESSAGE_SET_SYSTEM_AUDIO_MODE, + MESSAGE_REPORT_AUDIO_STATUS, + MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS, + MESSAGE_SYSTEM_AUDIO_MODE_STATUS, + MESSAGE_ROUTING_CHANGE, + MESSAGE_ROUTING_INFORMATION, + MESSAGE_ACTIVE_SOURCE, + MESSAGE_GIVE_PHYSICAL_ADDRESS, + MESSAGE_REPORT_PHYSICAL_ADDRESS, + MESSAGE_REQUEST_ACTIVE_SOURCE, + MESSAGE_SET_STREAM_PATH, + MESSAGE_DEVICE_VENDOR_ID, + MESSAGE_VENDOR_COMMAND, + MESSAGE_VENDOR_REMOTE_BUTTON_DOWN, + MESSAGE_VENDOR_REMOTE_BUTTON_UP, + MESSAGE_GIVE_DEVICE_VENDOR_ID, + MESSAGE_MENU_REQUEST, + MESSAGE_MENU_STATUS, + MESSAGE_GIVE_DEVICE_POWER_STATUS, + MESSAGE_REPORT_POWER_STATUS, + MESSAGE_GET_MENU_LANGUAGE, + MESSAGE_SELECT_ANALOG_SERVICE, + MESSAGE_SELECT_DIGITAL_SERVICE, + MESSAGE_SET_DIGITAL_TIMER, + MESSAGE_CLEAR_DIGITAL_TIMER, + MESSAGE_SET_AUDIO_RATE, + MESSAGE_INACTIVE_SOURCE, + MESSAGE_CEC_VERSION, + MESSAGE_GET_CEC_VERSION, + MESSAGE_VENDOR_COMMAND_WITH_ID, + MESSAGE_CLEAR_EXTERNAL_TIMER, + MESSAGE_SET_EXTERNAL_TIMER, + MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, + MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, + MESSAGE_GIVE_FEATURES, + MESSAGE_REPORT_FEATURES, + MESSAGE_REQUEST_CURRENT_LATENCY, + MESSAGE_REPORT_CURRENT_LATENCY, + MESSAGE_INITIATE_ARC, + MESSAGE_REPORT_ARC_INITIATED, + MESSAGE_REPORT_ARC_TERMINATED, + MESSAGE_REQUEST_ARC_INITIATION, + MESSAGE_REQUEST_ARC_TERMINATION, + MESSAGE_TERMINATE_ARC, + MESSAGE_CDC_MESSAGE, + MESSAGE_ABORT, }) - public @interface FeatureOpcode {} + public @interface FeatureOpcode { + } static final int MESSAGE_FEATURE_ABORT = 0x00; static final int MESSAGE_IMAGE_VIEW_ON = 0x04; @@ -225,6 +230,10 @@ final class Constants { static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2; static final int MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3; static final int MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4; + static final int MESSAGE_GIVE_FEATURES = 0xA5; + static final int MESSAGE_REPORT_FEATURES = 0xA6; + static final int MESSAGE_REQUEST_CURRENT_LATENCY = 0xA7; + static final int MESSAGE_REPORT_CURRENT_LATENCY = 0xA8; static final int MESSAGE_INITIATE_ARC = 0xC0; static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1; static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2; @@ -501,6 +510,35 @@ final class Constants { static final int VERSION_1_4 = 0x05; static final int VERSION_2_0 = 0x06; + static final int ALL_DEVICE_TYPES_TV = 7; + static final int ALL_DEVICE_TYPES_RECORDER = 6; + static final int ALL_DEVICE_TYPES_TUNER = 5; + static final int ALL_DEVICE_TYPES_PLAYBACK = 4; + static final int ALL_DEVICE_TYPES_AUDIO_SYSTEM = 3; + static final int ALL_DEVICE_TYPES_SWITCH = 2; + + static final int DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN = 6; + static final int DEVICE_FEATURE_TV_SUPPORTS_SET_OSD_STRING = 5; + static final int DEVICE_FEATURE_SUPPORTS_DECK_CONTROL = 4; + static final int DEVICE_FEATURE_SUPPORTS_SET_AUDIO_RATE = 3; + static final int DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX = 2; + static final int DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX = 1; + + static final int RC_PROFILE_TV = 0; + static final int RC_PROFILE_SOURCE = 1; + + static final int RC_PROFILE_TV_NONE = 0x0; + static final int RC_PROFILE_TV_ONE = 0x2; + static final int RC_PROFILE_TV_TWO = 0x6; + static final int RC_PROFILE_TV_THREE = 0xA; + static final int RC_PROFILE_TV_FOUR = 0xE; + + static final int RC_PROFILE_SOURCE_HANDLES_ROOT_MENU = 4; + static final int RC_PROFILE_SOURCE_HANDLES_SETUP_MENU = 3; + static final int RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU = 2; + static final int RC_PROFILE_SOURCE_HANDLES_TOP_MENU = 1; + static final int RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU = 0; + private Constants() { /* cannot be instantiated */ } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 38eb7fb7fe0b..e7f302c1977a 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -351,6 +351,8 @@ abstract class HdmiCecLocalDevice { return handleRequestShortAudioDescriptor(message); case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR: return handleReportShortAudioDescriptor(message); + case Constants.MESSAGE_GIVE_FEATURES: + return handleGiveFeatures(message); default: return false; } @@ -551,6 +553,33 @@ abstract class HdmiCecLocalDevice { return false; } + protected abstract int getRcProfile(); + + protected abstract List<Integer> getRcFeatures(); + + protected abstract List<Integer> getDeviceFeatures(); + + protected boolean handleGiveFeatures(HdmiCecMessage message) { + if (mService.getCecVersion() < Constants.VERSION_2_0) { + return false; + } + + List<Integer> localDeviceTypes = new ArrayList<>(); + for (HdmiCecLocalDevice localDevice : mService.getAllLocalDevices()) { + localDeviceTypes.add(localDevice.mDeviceType); + } + + + int rcProfile = getRcProfile(); + List<Integer> rcFeatures = getRcFeatures(); + List<Integer> deviceFeatures = getDeviceFeatures(); + + mService.sendCecCommand( + HdmiCecMessageBuilder.buildReportFeatures(mAddress, mService.getCecVersion(), + localDeviceTypes, rcProfile, rcFeatures, deviceFeatures)); + return true; + } + @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 9dc00792f80b..4110de6fee90 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -47,6 +47,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiUtils.CodecSad; import com.android.server.hdmi.HdmiUtils.DeviceConfig; +import com.google.android.collect.Lists; + import org.xmlpull.v1.XmlPullParserException; import java.io.File; @@ -176,6 +178,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { } @Override + protected List<Integer> getDeviceFeatures() { + return Lists.newArrayList(Constants.DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX); + } + + @Override @ServiceThreadOnly void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java index 960510693f6a..62b7d8f95f5a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java @@ -28,6 +28,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.Constants.LocalActivePort; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; +import com.google.android.collect.Lists; + import java.util.List; /** @@ -233,6 +235,24 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { // do nothing } + @Override + protected int getRcProfile() { + return Constants.RC_PROFILE_SOURCE; + } + + @Override + protected List<Integer> getRcFeatures() { + return Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, + Constants.RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, + Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, + Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU); + } + + @Override + protected List<Integer> getDeviceFeatures() { + return Lists.newArrayList(); + } + // Active source claiming needs to be handled in Service // since service can decide who will be the active source when the device supports // multiple device types in this method. diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index c2e80caadd3b..8cf6c9757fe8 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -51,6 +51,8 @@ import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; +import com.google.android.collect.Lists; + import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -1479,6 +1481,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + protected int getRcProfile() { + return Constants.RC_PROFILE_TV; + } + + @Override + protected List<Integer> getRcFeatures() { + return Lists.newArrayList(Constants.RC_PROFILE_TV_NONE); + } + + @Override + protected List<Integer> getDeviceFeatures() { + return Lists.newArrayList(Constants.DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX, + Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN); + } + + @Override protected void sendStandby(int deviceId) { HdmiDeviceInfo targetDevice = mService.getHdmiCecNetwork().getDeviceInfo(deviceId); if (targetDevice == null) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java index 7a6ce8de8c24..c85fd50c62fe 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java @@ -18,6 +18,8 @@ package com.android.server.hdmi; import android.annotation.Nullable; +import com.android.server.hdmi.Constants.FeatureOpcode; + import libcore.util.EmptyArray; import java.util.Arrays; @@ -126,7 +128,7 @@ public final class HdmiCecMessage { return s.toString(); } - private static String opcodeToString(int opcode) { + private static String opcodeToString(@FeatureOpcode int opcode) { switch (opcode) { case Constants.MESSAGE_FEATURE_ABORT: return "Feature Abort"; @@ -264,6 +266,14 @@ public final class HdmiCecMessage { return "Request ARC Initiation"; case Constants.MESSAGE_REQUEST_ARC_TERMINATION: return "Request ARC Termination"; + case Constants.MESSAGE_GIVE_FEATURES: + return "Give Features"; + case Constants.MESSAGE_REPORT_FEATURES: + return "Report Features"; + case Constants.MESSAGE_REQUEST_CURRENT_LATENCY: + return "Request Current Latency"; + case Constants.MESSAGE_REPORT_CURRENT_LATENCY: + return "Report Current Latency"; case Constants.MESSAGE_TERMINATE_ARC: return "Terminate ARC"; case Constants.MESSAGE_CDC_MESSAGE: diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 653323de8d60..1a481b632606 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -16,10 +16,14 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiDeviceInfo; + import com.android.server.hdmi.Constants.AudioCodec; +import com.android.server.hdmi.Constants.CecVersion; import java.io.UnsupportedEncodingException; import java.util.Arrays; +import java.util.List; /** * A helper class to build {@link HdmiCecMessage} from various cec commands. @@ -688,6 +692,40 @@ public class HdmiCecMessageBuilder { return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params); } + static HdmiCecMessage buildGiveFeatures(int src, int dest) { + return buildCommand(src, dest, Constants.MESSAGE_GIVE_FEATURES); + } + + static HdmiCecMessage buildReportFeatures(int src, @CecVersion int cecVersion, + List<Integer> allDeviceTypes, int rcProfile, List<Integer> rcFeatures, + List<Integer> deviceFeatures) { + byte cecVersionByte = (byte) (cecVersion & 0xFF); + byte deviceTypes = 0; + for (Integer deviceType : allDeviceTypes) { + deviceTypes |= 1 << hdmiDeviceInfoDeviceTypeToShiftValue(deviceType); + } + + byte rcProfileByte = 0; + rcProfileByte |= rcProfile << 6; + if (rcProfile == Constants.RC_PROFILE_SOURCE) { + for (Integer rcFeature : rcFeatures) { + rcProfileByte |= 1 << rcFeature; + } + } else { + byte rcProfileTv = (byte) (rcFeatures.get(0) & 0xFFFF); + rcProfileByte |= rcProfileTv; + } + + byte deviceFeaturesByte = 0; + for (Integer deviceFeature : deviceFeatures) { + deviceFeaturesByte |= 1 << deviceFeature; + } + + byte[] params = {cecVersionByte, deviceTypes, rcProfileByte, deviceFeaturesByte}; + return buildCommand(src, Constants.ADDR_BROADCAST, Constants.MESSAGE_REPORT_FEATURES, + params); + } + /***** Please ADD new buildXXX() methods above. ******/ /** @@ -738,4 +776,23 @@ public class HdmiCecMessageBuilder { (byte) (physicalAddress & 0xFF) }; } + + private static int hdmiDeviceInfoDeviceTypeToShiftValue(int deviceType) { + switch (deviceType) { + case HdmiDeviceInfo.DEVICE_TV: + return Constants.ALL_DEVICE_TYPES_TV; + case HdmiDeviceInfo.DEVICE_RECORDER: + return Constants.ALL_DEVICE_TYPES_RECORDER; + case HdmiDeviceInfo.DEVICE_TUNER: + return Constants.ALL_DEVICE_TYPES_TUNER; + case HdmiDeviceInfo.DEVICE_PLAYBACK: + return Constants.ALL_DEVICE_TYPES_PLAYBACK; + case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM: + return Constants.ALL_DEVICE_TYPES_AUDIO_SYSTEM; + case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH: + return Constants.ALL_DEVICE_TYPES_SWITCH; + default: + throw new IllegalArgumentException("Unhandled device type: " + deviceType); + } + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index fe97f701e089..cdd92166964d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -211,6 +211,17 @@ public class HdmiCecMessageValidator { new OneByteRangeValidator(0x00, 0x06), DEST_DIRECT); + // Messages for Feature Discovery. + addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, DEST_DIRECT); + addValidationInfo(Constants.MESSAGE_REPORT_FEATURES, new VariableLengthValidator(4, 14), + DEST_BROADCAST); + + // Messages for Dynamic Auto Lipsync + addValidationInfo(Constants.MESSAGE_REQUEST_CURRENT_LATENCY, physicalAddressValidator, + DEST_BROADCAST); + addValidationInfo(Constants.MESSAGE_REPORT_CURRENT_LATENCY, + new VariableLengthValidator(4, 14), DEST_BROADCAST); + // All Messages for the ARC have no parameters. // Messages for the Capability Discovery and Control. 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 e54f2c9e6b2e..2f49fb79c3dc 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -42,6 +42,8 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.Arrays; +import java.util.Collections; +import java.util.List; @SmallTest @Presubmit @@ -80,6 +82,21 @@ public class HdmiCecLocalDeviceTest { @Override protected void setPreferredAddress(int addr) {} + + @Override + protected int getRcProfile() { + return 0; + } + + @Override + protected List<Integer> getRcFeatures() { + return Collections.emptyList(); + } + + @Override + protected List<Integer> getDeviceFeatures() { + return Collections.emptyList(); + } } private MyHdmiCecLocalDevice mHdmiLocalDevice; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java index f17173f61b69..6882ec1869ea 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java @@ -26,10 +26,14 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import com.google.android.collect.Lists; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.Collections; + @SmallTest @Presubmit @RunWith(JUnit4.class) @@ -88,6 +92,98 @@ public class HdmiCecMessageBuilderTest { buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E")); } + @Test + public void buildGiveFeatures() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildGiveFeatures(ADDR_PLAYBACK_1, ADDR_TV); + + assertThat(message).isEqualTo(buildMessage("40:A5")); + } + + @Test + public void buildReportFeatures_basicTv_1_4() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_1_4, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("0F:A6:05:80:00:00")); + } + + @Test + public void buildReportFeatures_basicPlayback_1_4() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1, + Constants.VERSION_1_4, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("4F:A6:05:10:00:00")); + } + + @Test + public void buildReportFeatures_basicPlaybackAudioSystem_1_4() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1, + Constants.VERSION_1_4, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK, + HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("4F:A6:05:18:00:00")); + } + + @Test + public void buildReportFeatures_basicTv_2_0() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_2_0, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:00")); + } + + @Test + public void buildReportFeatures_remoteControlTv_2_0() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_2_0, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_ONE), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:02:00")); + } + + @Test + public void buildReportFeatures_remoteControlPlayback_2_0() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_2_0, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE, + Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU), Collections.emptyList()); + + assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:00")); + } + + @Test + public void buildReportFeatures_deviceFeaturesTv_2_0() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_2_0, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV, + Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), + Lists.newArrayList(Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN)); + + assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:40")); + } + + @Test + public void buildReportFeatures_deviceFeaturesPlayback_2_0() { + HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV, + Constants.VERSION_2_0, + Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE, + Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU, + Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU), + Lists.newArrayList(Constants.DEVICE_FEATURE_SUPPORTS_DECK_CONTROL)); + + assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:10")); + } + /** * Build a CEC message from a hex byte string with bytes separated by {@code :}. * @@ -100,7 +196,7 @@ public class HdmiCecMessageBuilderTest { int opcode = Integer.parseInt(parts[1], 16); byte[] params = new byte[parts.length - 2]; for (int i = 0; i < params.length; i++) { - params[i] = Byte.parseByte(parts[i + 2], 16); + params[i] = (byte) Integer.parseInt(parts[i + 2], 16); } return new HdmiCecMessage(src, dest, opcode, params); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index 553df3bafd00..c1532f21adbf 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -353,6 +353,24 @@ public class HdmiCecMessageValidatorTest { assertMessageValidity("40:35:EE:52:4A").isEqualTo(ERROR_PARAMETER); } + @Test + public void isValid_giveFeatures() { + assertMessageValidity("40:A5").isEqualTo(OK); + + assertMessageValidity("4F:A5").isEqualTo(ERROR_DESTINATION); + assertMessageValidity("F0:A5").isEqualTo(ERROR_SOURCE); + } + + @Test + public void isValid_reportFeatures() { + assertMessageValidity("0F:A6:05:80:00:00").isEqualTo(OK); + + assertMessageValidity("04:A6:05:80:00:00").isEqualTo(ERROR_DESTINATION); + assertMessageValidity("FF:A6:05:80:00:00").isEqualTo(ERROR_SOURCE); + + assertMessageValidity("0F:A6").isEqualTo(ERROR_PARAMETER_SHORT); + } + private IntegerSubject assertMessageValidity(String message) { return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message))); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java index 74a00521d7f4..c212bf868c76 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java @@ -38,6 +38,8 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Tests for {@link HdmiControlServiceBinderAPITest} class. @@ -99,6 +101,21 @@ public class HdmiControlServiceBinderAPITest { protected void setCanGoToStandby(boolean canGoToStandby) { mCanGoToStandby = canGoToStandby; } + + @Override + protected int getRcProfile() { + return 0; + } + + @Override + protected List<Integer> getRcFeatures() { + return Collections.emptyList(); + } + + @Override + protected List<Integer> getDeviceFeatures() { + return Collections.emptyList(); + } } private static final String TAG = "HdmiControlServiceBinderAPITest"; 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 68b46c408028..dea3896f1b77 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -54,6 +54,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Arrays; /** * Tests for {@link HdmiControlService} class. @@ -421,6 +422,42 @@ public class HdmiControlServiceTest { assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0); } + @Test + public void handleGiveFeatures_cec14_featureAbort() { + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_1_4); + mHdmiControlService.setControlEnabled(true); + mTestLooper.dispatchAll(); + + mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV, + Constants.ADDR_PLAYBACK_1)); + mTestLooper.dispatchAll(); + + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + Constants.ADDR_PLAYBACK_1, Constants.ADDR_TV, Constants.MESSAGE_GIVE_FEATURES, + Constants.ABORT_UNRECOGNIZED_OPCODE); + assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); + } + + @Test + public void handleGiveFeatures_cec20_reportsFeatures() { + Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION, + Constants.VERSION_2_0); + mHdmiControlService.setControlEnabled(true); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mTestLooper.dispatchAll(); + + mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV, + Constants.ADDR_PLAYBACK_1)); + mTestLooper.dispatchAll(); + + HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures( + Constants.ADDR_PLAYBACK_1, Constants.VERSION_2_0, + Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM), + mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(), + mMyPlaybackDevice.getDeviceFeatures()); + assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures); + } private static class VolumeControlFeatureCallback extends IHdmiCecVolumeControlFeatureListener.Stub { |