396 lines
15 KiB
Java
396 lines
15 KiB
Java
/*
|
|
* 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 input that is not {@link #FEATURE_SUPPORT_UNKNOWN}. If neither is equal to
|
|
* {@link #FEATURE_SUPPORT_UNKNOWN}, returns the second input.
|
|
*/
|
|
private static @FeatureSupportStatus int updateFeatureSupportStatus(
|
|
@FeatureSupportStatus int oldStatus, @FeatureSupportStatus int newStatus) {
|
|
if (newStatus == FEATURE_SUPPORT_UNKNOWN) {
|
|
return oldStatus;
|
|
} else {
|
|
return newStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Updates all fields with those in a 'new' instance of {@link DeviceFeatures}.
|
|
* All fields are replaced with those in the new instance, except when the field is
|
|
* {@link #FEATURE_SUPPORT_UNKNOWN} in the new instance.
|
|
*/
|
|
@NonNull
|
|
public Builder update(DeviceFeatures newDeviceFeatures) {
|
|
mRecordTvScreenSupport = updateFeatureSupportStatus(mRecordTvScreenSupport,
|
|
newDeviceFeatures.getRecordTvScreenSupport());
|
|
mOsdStringSupport = updateFeatureSupportStatus(mOsdStringSupport,
|
|
newDeviceFeatures.getSetOsdStringSupport());
|
|
mDeckControlSupport = updateFeatureSupportStatus(mDeckControlSupport,
|
|
newDeviceFeatures.getDeckControlSupport());
|
|
mSetAudioRateSupport = updateFeatureSupportStatus(mSetAudioRateSupport,
|
|
newDeviceFeatures.getSetAudioRateSupport());
|
|
mArcTxSupport = updateFeatureSupportStatus(mArcTxSupport,
|
|
newDeviceFeatures.getArcTxSupport());
|
|
mArcRxSupport = updateFeatureSupportStatus(mArcRxSupport,
|
|
newDeviceFeatures.getArcRxSupport());
|
|
mSetAudioVolumeLevelSupport = updateFeatureSupportStatus(mSetAudioVolumeLevelSupport,
|
|
newDeviceFeatures.getSetAudioVolumeLevelSupport());
|
|
return this;
|
|
}
|
|
}
|
|
}
|