diff options
| author | Yan Han <yanha@google.com> | 2021-12-15 10:02:16 +0100 |
|---|---|---|
| committer | Yan Han <yanha@google.com> | 2022-01-14 18:36:11 +0100 |
| commit | 23181eb8a6d657108bcde84f0e29dbfe5be760de (patch) | |
| tree | e0adcefc77a3f744b0da86ff66674b61434923d7 /core/java | |
| parent | 8bd2ec2f22901554578f7f73a579bd9b802cc758 (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.java | 358 | ||||
| -rw-r--r-- | core/java/android/hardware/hdmi/HdmiDeviceInfo.java | 33 |
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 |
