summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorYan Han <yanha@google.com>2021-12-15 10:02:16 +0100
committerYan Han <yanha@google.com>2022-01-14 18:36:11 +0100
commit23181eb8a6d657108bcde84f0e29dbfe5be760de (patch)
treee0adcefc77a3f744b0da86ff66674b61434923d7 /core/java
parent8bd2ec2f22901554578f7f73a579bd9b802cc758 (diff)
Add CEC feature tracking to HdmiDeviceInfo
HdmiDeviceInfo now contains an object for tracking features whose support is communicated in the [Device Features] operand. Bug: 204854610 Test: atest DeviceFeaturesTest Change-Id: Id2e19fb2e4480b5ed88529fd15012c7abad5d3a7
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/hardware/hdmi/DeviceFeatures.java358
-rw-r--r--core/java/android/hardware/hdmi/HdmiDeviceInfo.java33
2 files changed, 391 insertions, 0 deletions
diff --git a/core/java/android/hardware/hdmi/DeviceFeatures.java b/core/java/android/hardware/hdmi/DeviceFeatures.java
new file mode 100644
index 000000000000..fb42e62effa0
--- /dev/null
+++ b/core/java/android/hardware/hdmi/DeviceFeatures.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Immutable class that stores support status for features in the [Device Features] operand.
+ * Each feature may be supported, be not supported, or have an unknown support status.
+ *
+ * @hide
+ */
+public class DeviceFeatures {
+
+ @IntDef({
+ FEATURE_NOT_SUPPORTED,
+ FEATURE_SUPPORTED,
+ FEATURE_SUPPORT_UNKNOWN
+ })
+ public @interface FeatureSupportStatus {};
+
+ public static final int FEATURE_NOT_SUPPORTED = 0;
+ public static final int FEATURE_SUPPORTED = 1;
+ public static final int FEATURE_SUPPORT_UNKNOWN = 2;
+
+ /**
+ * Instance representing no knowledge of any feature's support.
+ */
+ @NonNull
+ public static final DeviceFeatures ALL_FEATURES_SUPPORT_UNKNOWN =
+ new Builder(FEATURE_SUPPORT_UNKNOWN).build();
+
+ /**
+ * Instance representing no support for any feature.
+ */
+ @NonNull
+ public static final DeviceFeatures NO_FEATURES_SUPPORTED =
+ new Builder(FEATURE_NOT_SUPPORTED).build();
+
+ @FeatureSupportStatus private final int mRecordTvScreenSupport;
+ @FeatureSupportStatus private final int mSetOsdStringSupport;
+ @FeatureSupportStatus private final int mDeckControlSupport;
+ @FeatureSupportStatus private final int mSetAudioRateSupport;
+ @FeatureSupportStatus private final int mArcTxSupport;
+ @FeatureSupportStatus private final int mArcRxSupport;
+ @FeatureSupportStatus private final int mSetAudioVolumeLevelSupport;
+
+ private DeviceFeatures(@NonNull Builder builder) {
+ this.mRecordTvScreenSupport = builder.mRecordTvScreenSupport;
+ this.mSetOsdStringSupport = builder.mOsdStringSupport;
+ this.mDeckControlSupport = builder.mDeckControlSupport;
+ this.mSetAudioRateSupport = builder.mSetAudioRateSupport;
+ this.mArcTxSupport = builder.mArcTxSupport;
+ this.mArcRxSupport = builder.mArcRxSupport;
+ this.mSetAudioVolumeLevelSupport = builder.mSetAudioVolumeLevelSupport;
+ }
+
+ /**
+ * Converts an instance to a builder.
+ */
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ /**
+ * Constructs an instance from a [Device Features] operand.
+ *
+ * Bit 7 of [Device Features] is currently ignored. It indicates whether the operand spans more
+ * than one byte, but only the first byte contains information as of CEC 2.0.
+ *
+ * @param deviceFeaturesOperand The [Device Features] operand to parse.
+ * @return Instance representing the [Device Features] operand.
+ */
+ @NonNull
+ public static DeviceFeatures fromOperand(@NonNull byte[] deviceFeaturesOperand) {
+ Builder builder = new Builder(FEATURE_SUPPORT_UNKNOWN);
+
+ // Read feature support status from the bits of [Device Features]
+ if (deviceFeaturesOperand.length >= 1) {
+ byte b = deviceFeaturesOperand[0];
+ builder
+ .setRecordTvScreenSupport(bitToFeatureSupportStatus(((b >> 6) & 1) == 1))
+ .setSetOsdStringSupport(bitToFeatureSupportStatus(((b >> 5) & 1) == 1))
+ .setDeckControlSupport(bitToFeatureSupportStatus(((b >> 4) & 1) == 1))
+ .setSetAudioRateSupport(bitToFeatureSupportStatus(((b >> 3) & 1) == 1))
+ .setArcTxSupport(bitToFeatureSupportStatus(((b >> 2) & 1) == 1))
+ .setArcRxSupport(bitToFeatureSupportStatus(((b >> 1) & 1) == 1))
+ .setSetAudioVolumeLevelSupport(bitToFeatureSupportStatus((b & 1) == 1));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns the [Device Features] operand corresponding to this instance.
+ * {@link #FEATURE_SUPPORT_UNKNOWN} maps to 0, indicating no support.
+ *
+ * As of CEC 2.0, the returned byte array will always be of length 1.
+ */
+ @NonNull
+ public byte[] toOperand() {
+ byte result = 0;
+
+ if (mRecordTvScreenSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 6);
+ if (mSetOsdStringSupport == FEATURE_SUPPORTED) result = (byte) (1 << 5);
+ if (mDeckControlSupport == FEATURE_SUPPORTED) result = (byte) (1 << 4);
+ if (mSetAudioRateSupport == FEATURE_SUPPORTED) result = (byte) (1 << 3);
+ if (mArcTxSupport == FEATURE_SUPPORTED) result = (byte) (1 << 2);
+ if (mArcRxSupport == FEATURE_SUPPORTED) result = (byte) (1 << 1);
+ if (mSetAudioVolumeLevelSupport == FEATURE_SUPPORTED) result = (byte) 1;
+
+ return new byte[]{ result };
+ }
+
+ @FeatureSupportStatus
+ private static int bitToFeatureSupportStatus(boolean bit) {
+ return bit ? FEATURE_SUPPORTED : FEATURE_NOT_SUPPORTED;
+ }
+
+ /**
+ * Returns whether the device is a TV that supports <Record TV Screen>.
+ */
+ @FeatureSupportStatus
+ public int getRecordTvScreenSupport() {
+ return mRecordTvScreenSupport;
+ }
+
+ /**
+ * Returns whether the device is a TV that supports <Set OSD String>.
+ */
+ @FeatureSupportStatus
+ public int getSetOsdStringSupport() {
+ return mSetOsdStringSupport;
+ }
+
+ /**
+ * Returns whether the device supports being controlled by Deck Control.
+ */
+ @FeatureSupportStatus
+ public int getDeckControlSupport() {
+ return mDeckControlSupport;
+ }
+
+ /**
+ * Returns whether the device is a Source that supports <Set Audio Rate>.
+ */
+ @FeatureSupportStatus
+ public int getSetAudioRateSupport() {
+ return mSetAudioRateSupport;
+ }
+
+ /**
+ * Returns whether the device is a Sink that supports ARC Tx.
+ */
+ @FeatureSupportStatus
+ public int getArcTxSupport() {
+ return mArcTxSupport;
+ }
+
+ /**
+ * Returns whether the device is a Source that supports ARC Rx.
+ */
+ @FeatureSupportStatus
+ public int getArcRxSupport() {
+ return mArcRxSupport;
+ }
+
+ /**
+ * Returns whether the device supports <Set Audio Volume Level>.
+ */
+ @FeatureSupportStatus
+ public int getSetAudioVolumeLevelSupport() {
+ return mSetAudioVolumeLevelSupport;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof DeviceFeatures)) {
+ return false;
+ }
+
+ DeviceFeatures other = (DeviceFeatures) obj;
+ return mRecordTvScreenSupport == other.mRecordTvScreenSupport
+ && mSetOsdStringSupport == other.mSetOsdStringSupport
+ && mDeckControlSupport == other.mDeckControlSupport
+ && mSetAudioRateSupport == other.mSetAudioRateSupport
+ && mArcTxSupport == other.mArcTxSupport
+ && mArcRxSupport == other.mArcRxSupport
+ && mSetAudioVolumeLevelSupport == other.mSetAudioVolumeLevelSupport;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(
+ mRecordTvScreenSupport,
+ mSetOsdStringSupport,
+ mDeckControlSupport,
+ mSetAudioRateSupport,
+ mArcTxSupport,
+ mArcRxSupport,
+ mSetAudioVolumeLevelSupport
+ );
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("Device features: ");
+ s.append("record_tv_screen: ")
+ .append(featureSupportStatusToString(mRecordTvScreenSupport)).append(" ");
+ s.append("set_osd_string: ")
+ .append(featureSupportStatusToString(mSetOsdStringSupport)).append(" ");
+ s.append("deck_control: ")
+ .append(featureSupportStatusToString(mDeckControlSupport)).append(" ");
+ s.append("set_audio_rate: ")
+ .append(featureSupportStatusToString(mSetAudioRateSupport)).append(" ");
+ s.append("arc_tx: ")
+ .append(featureSupportStatusToString(mArcTxSupport)).append(" ");
+ s.append("arc_rx: ")
+ .append(featureSupportStatusToString(mArcRxSupport)).append(" ");
+ s.append("set_audio_volume_level: ")
+ .append(featureSupportStatusToString(mSetAudioVolumeLevelSupport)).append(" ");
+ return s.toString();
+ }
+
+ @NonNull
+ private static String featureSupportStatusToString(@FeatureSupportStatus int status) {
+ switch (status) {
+ case FEATURE_SUPPORTED:
+ return "Y";
+ case FEATURE_NOT_SUPPORTED:
+ return "N";
+ case FEATURE_SUPPORT_UNKNOWN:
+ default:
+ return "?";
+ }
+ }
+
+ /**
+ * Builder for {@link DeviceFeatures} instances.
+ */
+ public static final class Builder {
+ @FeatureSupportStatus private int mRecordTvScreenSupport;
+ @FeatureSupportStatus private int mOsdStringSupport;
+ @FeatureSupportStatus private int mDeckControlSupport;
+ @FeatureSupportStatus private int mSetAudioRateSupport;
+ @FeatureSupportStatus private int mArcTxSupport;
+ @FeatureSupportStatus private int mArcRxSupport;
+ @FeatureSupportStatus private int mSetAudioVolumeLevelSupport;
+
+ private Builder(@FeatureSupportStatus int defaultFeatureSupportStatus) {
+ mRecordTvScreenSupport = defaultFeatureSupportStatus;
+ mOsdStringSupport = defaultFeatureSupportStatus;
+ mDeckControlSupport = defaultFeatureSupportStatus;
+ mSetAudioRateSupport = defaultFeatureSupportStatus;
+ mArcTxSupport = defaultFeatureSupportStatus;
+ mArcRxSupport = defaultFeatureSupportStatus;
+ mSetAudioVolumeLevelSupport = defaultFeatureSupportStatus;
+ }
+
+ private Builder(DeviceFeatures info) {
+ mRecordTvScreenSupport = info.getRecordTvScreenSupport();
+ mOsdStringSupport = info.getSetOsdStringSupport();
+ mDeckControlSupport = info.getDeckControlSupport();
+ mSetAudioRateSupport = info.getSetAudioRateSupport();
+ mArcTxSupport = info.getArcTxSupport();
+ mArcRxSupport = info.getArcRxSupport();
+ mSetAudioVolumeLevelSupport = info.getSetAudioVolumeLevelSupport();
+ }
+
+ /**
+ * Creates a new {@link DeviceFeatures} object.
+ */
+ public DeviceFeatures build() {
+ return new DeviceFeatures(this);
+ }
+
+ /**
+ * Sets the value for {@link #getRecordTvScreenSupport()}.
+ */
+ @NonNull
+ public Builder setRecordTvScreenSupport(@FeatureSupportStatus int recordTvScreenSupport) {
+ mRecordTvScreenSupport = recordTvScreenSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getSetOsdStringSupport()}.
+ */
+ @NonNull
+ public Builder setSetOsdStringSupport(@FeatureSupportStatus int setOsdStringSupport) {
+ mOsdStringSupport = setOsdStringSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getDeckControlSupport()}.
+ */
+ @NonNull
+ public Builder setDeckControlSupport(@FeatureSupportStatus int deckControlSupport) {
+ mDeckControlSupport = deckControlSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getSetAudioRateSupport()}.
+ */
+ @NonNull
+ public Builder setSetAudioRateSupport(@FeatureSupportStatus int setAudioRateSupport) {
+ mSetAudioRateSupport = setAudioRateSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getArcTxSupport()}.
+ */
+ @NonNull
+ public Builder setArcTxSupport(@FeatureSupportStatus int arcTxSupport) {
+ mArcTxSupport = arcTxSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getArcRxSupport()}.
+ */
+ @NonNull
+ public Builder setArcRxSupport(@FeatureSupportStatus int arcRxSupport) {
+ mArcRxSupport = arcRxSupport;
+ return this;
+ }
+
+ /**
+ * Sets the value for {@link #getSetAudioRateSupport()}.
+ */
+ @NonNull
+ public Builder setSetAudioVolumeLevelSupport(
+ @FeatureSupportStatus int setAudioVolumeLevelSupport) {
+ mSetAudioVolumeLevelSupport = setAudioVolumeLevelSupport;
+ return this;
+ }
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
index 96255bcbdff7..ca90661d56aa 100644
--- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -124,6 +124,7 @@ public class HdmiDeviceInfo implements Parcelable {
private final int mVendorId;
private final String mDisplayName;
private final int mDevicePowerStatus;
+ private final DeviceFeatures mDeviceFeatures;
// MHL only parameters.
private final int mDeviceId;
@@ -198,6 +199,7 @@ public class HdmiDeviceInfo implements Parcelable {
mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
mDisplayName = "Inactive";
mVendorId = 0;
+ mDeviceFeatures = DeviceFeatures.ALL_FEATURES_SUPPORT_UNKNOWN;
mDeviceId = -1;
mAdopterId = -1;
@@ -222,6 +224,7 @@ public class HdmiDeviceInfo implements Parcelable {
this.mVendorId = builder.mVendorId;
this.mDisplayName = builder.mDisplayName;
this.mDevicePowerStatus = builder.mDevicePowerStatus;
+ this.mDeviceFeatures = builder.mDeviceFeatures;
this.mDeviceId = builder.mDeviceId;
this.mAdopterId = builder.mAdopterId;
@@ -295,6 +298,15 @@ public class HdmiDeviceInfo implements Parcelable {
}
/**
+ * Returns the CEC features that this device supports.
+ *
+ * @hide
+ */
+ public DeviceFeatures getDeviceFeatures() {
+ return mDeviceFeatures;
+ }
+
+ /**
* Returns the id to be used for CEC device.
*
* @param address logical address of CEC device
@@ -521,6 +533,11 @@ public class HdmiDeviceInfo implements Parcelable {
s.append("physical_address: ").append(String.format("0x%04X", mPhysicalAddress));
s.append(" ");
s.append("port_id: ").append(mPortId);
+
+ if (mHdmiDeviceType == HDMI_DEVICE_TYPE_CEC) {
+ s.append("\n ").append(mDeviceFeatures.toString());
+ }
+
return s.toString();
}
@@ -581,6 +598,7 @@ public class HdmiDeviceInfo implements Parcelable {
private int mVendorId = VENDOR_ID_UNKNOWN;
private String mDisplayName = "";
private int mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+ private DeviceFeatures mDeviceFeatures;
// MHL parameters
private int mDeviceId = -1;
@@ -588,6 +606,11 @@ public class HdmiDeviceInfo implements Parcelable {
private Builder(int hdmiDeviceType) {
mHdmiDeviceType = hdmiDeviceType;
+ if (hdmiDeviceType == HDMI_DEVICE_TYPE_CEC) {
+ mDeviceFeatures = DeviceFeatures.ALL_FEATURES_SUPPORT_UNKNOWN;
+ } else {
+ mDeviceFeatures = DeviceFeatures.NO_FEATURES_SUPPORTED;
+ }
}
private Builder(@NonNull HdmiDeviceInfo hdmiDeviceInfo) {
@@ -602,6 +625,7 @@ public class HdmiDeviceInfo implements Parcelable {
mDevicePowerStatus = hdmiDeviceInfo.mDevicePowerStatus;
mDeviceId = hdmiDeviceInfo.mDeviceId;
mAdopterId = hdmiDeviceInfo.mAdopterId;
+ mDeviceFeatures = hdmiDeviceInfo.mDeviceFeatures;
}
/**
@@ -685,6 +709,15 @@ public class HdmiDeviceInfo implements Parcelable {
}
/**
+ * Sets the value for {@link #getDeviceFeatures()}.
+ */
+ @NonNull
+ public Builder setDeviceFeatures(DeviceFeatures deviceFeatures) {
+ this.mDeviceFeatures = deviceFeatures;
+ return this;
+ }
+
+ /**
* Sets the value for {@link #getDeviceId()}.
*/
@NonNull