• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.hdmi;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 
23 /**
24  * Immutable class that stores support status for features in the [Device Features] operand.
25  * Each feature may be supported, be not supported, or have an unknown support status.
26  *
27  * @hide
28  */
29 public class DeviceFeatures {
30 
31     @IntDef({
32             FEATURE_NOT_SUPPORTED,
33             FEATURE_SUPPORTED,
34             FEATURE_SUPPORT_UNKNOWN
35     })
36     public @interface FeatureSupportStatus {};
37 
38     public static final int FEATURE_NOT_SUPPORTED = 0;
39     public static final int FEATURE_SUPPORTED = 1;
40     public static final int FEATURE_SUPPORT_UNKNOWN = 2;
41 
42     /**
43      * Instance representing no knowledge of any feature's support.
44      */
45     @NonNull
46     public static final DeviceFeatures ALL_FEATURES_SUPPORT_UNKNOWN =
47             new Builder(FEATURE_SUPPORT_UNKNOWN).build();
48 
49     /**
50      * Instance representing no support for any feature.
51      */
52     @NonNull
53     public static final DeviceFeatures NO_FEATURES_SUPPORTED =
54             new Builder(FEATURE_NOT_SUPPORTED).build();
55 
56     @FeatureSupportStatus private final int mRecordTvScreenSupport;
57     @FeatureSupportStatus private final int mSetOsdStringSupport;
58     @FeatureSupportStatus private final int mDeckControlSupport;
59     @FeatureSupportStatus private final int mSetAudioRateSupport;
60     @FeatureSupportStatus private final int mArcTxSupport;
61     @FeatureSupportStatus private final int mArcRxSupport;
62     @FeatureSupportStatus private final int mSetAudioVolumeLevelSupport;
63 
DeviceFeatures(@onNull Builder builder)64     private DeviceFeatures(@NonNull Builder builder) {
65         this.mRecordTvScreenSupport = builder.mRecordTvScreenSupport;
66         this.mSetOsdStringSupport = builder.mOsdStringSupport;
67         this.mDeckControlSupport = builder.mDeckControlSupport;
68         this.mSetAudioRateSupport = builder.mSetAudioRateSupport;
69         this.mArcTxSupport = builder.mArcTxSupport;
70         this.mArcRxSupport = builder.mArcRxSupport;
71         this.mSetAudioVolumeLevelSupport = builder.mSetAudioVolumeLevelSupport;
72     }
73 
74     /**
75      * Converts an instance to a builder.
76      */
toBuilder()77     public Builder toBuilder() {
78         return new Builder(this);
79     }
80 
81     /**
82      * Constructs an instance from a [Device Features] operand.
83      *
84      * Bit 7 of [Device Features] is currently ignored. It indicates whether the operand spans more
85      * than one byte, but only the first byte contains information as of CEC 2.0.
86      *
87      * @param deviceFeaturesOperand The [Device Features] operand to parse.
88      * @return Instance representing the [Device Features] operand.
89      */
90     @NonNull
fromOperand(@onNull byte[] deviceFeaturesOperand)91     public static DeviceFeatures fromOperand(@NonNull byte[] deviceFeaturesOperand) {
92         Builder builder = new Builder(FEATURE_SUPPORT_UNKNOWN);
93 
94         // Read feature support status from the bits of [Device Features]
95         if (deviceFeaturesOperand.length >= 1) {
96             byte b = deviceFeaturesOperand[0];
97             builder
98                     .setRecordTvScreenSupport(bitToFeatureSupportStatus(((b >> 6) & 1) == 1))
99                     .setSetOsdStringSupport(bitToFeatureSupportStatus(((b >> 5) & 1) == 1))
100                     .setDeckControlSupport(bitToFeatureSupportStatus(((b >> 4) & 1) == 1))
101                     .setSetAudioRateSupport(bitToFeatureSupportStatus(((b >> 3) & 1) == 1))
102                     .setArcTxSupport(bitToFeatureSupportStatus(((b >> 2) & 1) == 1))
103                     .setArcRxSupport(bitToFeatureSupportStatus(((b >> 1) & 1) == 1))
104                     .setSetAudioVolumeLevelSupport(bitToFeatureSupportStatus((b & 1) == 1));
105         }
106         return builder.build();
107     }
108 
109     /**
110      * Returns the input that is not {@link #FEATURE_SUPPORT_UNKNOWN}. If neither is equal to
111      * {@link #FEATURE_SUPPORT_UNKNOWN}, returns the second input.
112      */
updateFeatureSupportStatus( @eatureSupportStatus int oldStatus, @FeatureSupportStatus int newStatus)113     private static @FeatureSupportStatus int updateFeatureSupportStatus(
114             @FeatureSupportStatus int oldStatus, @FeatureSupportStatus int newStatus) {
115         if (newStatus == FEATURE_SUPPORT_UNKNOWN) {
116             return oldStatus;
117         } else {
118             return newStatus;
119         }
120     }
121 
122     /**
123      * Returns the [Device Features] operand corresponding to this instance.
124      * {@link #FEATURE_SUPPORT_UNKNOWN} maps to 0, indicating no support.
125      *
126      * As of CEC 2.0, the returned byte array will always be of length 1.
127      */
128     @NonNull
toOperand()129     public byte[] toOperand() {
130         byte result = 0;
131 
132         if (mRecordTvScreenSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 6);
133         if (mSetOsdStringSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 5);
134         if (mDeckControlSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 4);
135         if (mSetAudioRateSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 3);
136         if (mArcTxSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 2);
137         if (mArcRxSupport == FEATURE_SUPPORTED) result |= (byte) (1 << 1);
138         if (mSetAudioVolumeLevelSupport == FEATURE_SUPPORTED) result |= (byte) 1;
139 
140         return new byte[]{ result };
141     }
142 
143     @FeatureSupportStatus
bitToFeatureSupportStatus(boolean bit)144     private static int bitToFeatureSupportStatus(boolean bit) {
145         return bit ? FEATURE_SUPPORTED : FEATURE_NOT_SUPPORTED;
146     }
147 
148     /**
149      * Returns whether the device is a TV that supports <Record TV Screen>.
150      */
151     @FeatureSupportStatus
getRecordTvScreenSupport()152     public int getRecordTvScreenSupport() {
153         return mRecordTvScreenSupport;
154     }
155 
156     /**
157      * Returns whether the device is a TV that supports <Set OSD String>.
158      */
159     @FeatureSupportStatus
getSetOsdStringSupport()160     public int getSetOsdStringSupport() {
161         return mSetOsdStringSupport;
162     }
163 
164     /**
165      * Returns whether the device supports being controlled by Deck Control.
166      */
167     @FeatureSupportStatus
getDeckControlSupport()168     public int getDeckControlSupport() {
169         return mDeckControlSupport;
170     }
171 
172     /**
173      * Returns whether the device is a Source that supports <Set Audio Rate>.
174      */
175     @FeatureSupportStatus
getSetAudioRateSupport()176     public int getSetAudioRateSupport() {
177         return mSetAudioRateSupport;
178     }
179 
180     /**
181      * Returns whether the device is a Sink that supports ARC Tx.
182      */
183     @FeatureSupportStatus
getArcTxSupport()184     public int getArcTxSupport() {
185         return mArcTxSupport;
186     }
187 
188     /**
189      * Returns whether the device is a Source that supports ARC Rx.
190      */
191     @FeatureSupportStatus
getArcRxSupport()192     public int getArcRxSupport() {
193         return mArcRxSupport;
194     }
195 
196     /**
197      * Returns whether the device supports <Set Audio Volume Level>.
198      */
199     @FeatureSupportStatus
getSetAudioVolumeLevelSupport()200     public int getSetAudioVolumeLevelSupport() {
201         return mSetAudioVolumeLevelSupport;
202     }
203 
204     @Override
equals(@ullable Object obj)205     public boolean equals(@Nullable Object obj) {
206         if (!(obj instanceof DeviceFeatures)) {
207             return false;
208         }
209 
210         DeviceFeatures other = (DeviceFeatures) obj;
211         return mRecordTvScreenSupport == other.mRecordTvScreenSupport
212                 && mSetOsdStringSupport == other.mSetOsdStringSupport
213                 && mDeckControlSupport == other.mDeckControlSupport
214                 && mSetAudioRateSupport == other.mSetAudioRateSupport
215                 && mArcTxSupport == other.mArcTxSupport
216                 && mArcRxSupport == other.mArcRxSupport
217                 && mSetAudioVolumeLevelSupport == other.mSetAudioVolumeLevelSupport;
218     }
219 
220     @Override
hashCode()221     public int hashCode() {
222         return java.util.Objects.hash(
223                 mRecordTvScreenSupport,
224                 mSetOsdStringSupport,
225                 mDeckControlSupport,
226                 mSetAudioRateSupport,
227                 mArcTxSupport,
228                 mArcRxSupport,
229                 mSetAudioVolumeLevelSupport
230         );
231     }
232 
233     @NonNull
234     @Override
toString()235     public String toString() {
236         StringBuilder s = new StringBuilder();
237         s.append("Device features: ");
238         s.append("record_tv_screen: ")
239                 .append(featureSupportStatusToString(mRecordTvScreenSupport)).append(" ");
240         s.append("set_osd_string: ")
241                 .append(featureSupportStatusToString(mSetOsdStringSupport)).append(" ");
242         s.append("deck_control: ")
243                 .append(featureSupportStatusToString(mDeckControlSupport)).append(" ");
244         s.append("set_audio_rate: ")
245                 .append(featureSupportStatusToString(mSetAudioRateSupport)).append(" ");
246         s.append("arc_tx: ")
247                 .append(featureSupportStatusToString(mArcTxSupport)).append(" ");
248         s.append("arc_rx: ")
249                 .append(featureSupportStatusToString(mArcRxSupport)).append(" ");
250         s.append("set_audio_volume_level: ")
251                 .append(featureSupportStatusToString(mSetAudioVolumeLevelSupport)).append(" ");
252         return s.toString();
253     }
254 
255     @NonNull
featureSupportStatusToString(@eatureSupportStatus int status)256     private static String featureSupportStatusToString(@FeatureSupportStatus int status) {
257         switch (status) {
258             case FEATURE_SUPPORTED:
259                 return "Y";
260             case FEATURE_NOT_SUPPORTED:
261                 return "N";
262             case FEATURE_SUPPORT_UNKNOWN:
263             default:
264                 return "?";
265         }
266     }
267 
268     /**
269      * Builder for {@link DeviceFeatures} instances.
270      */
271     public static final class Builder {
272         @FeatureSupportStatus private int mRecordTvScreenSupport;
273         @FeatureSupportStatus private int mOsdStringSupport;
274         @FeatureSupportStatus private int mDeckControlSupport;
275         @FeatureSupportStatus private int mSetAudioRateSupport;
276         @FeatureSupportStatus private int mArcTxSupport;
277         @FeatureSupportStatus private int mArcRxSupport;
278         @FeatureSupportStatus private int mSetAudioVolumeLevelSupport;
279 
Builder(@eatureSupportStatus int defaultFeatureSupportStatus)280         private Builder(@FeatureSupportStatus int defaultFeatureSupportStatus) {
281             mRecordTvScreenSupport = defaultFeatureSupportStatus;
282             mOsdStringSupport = defaultFeatureSupportStatus;
283             mDeckControlSupport = defaultFeatureSupportStatus;
284             mSetAudioRateSupport = defaultFeatureSupportStatus;
285             mArcTxSupport = defaultFeatureSupportStatus;
286             mArcRxSupport = defaultFeatureSupportStatus;
287             mSetAudioVolumeLevelSupport = defaultFeatureSupportStatus;
288         }
289 
Builder(DeviceFeatures info)290         private Builder(DeviceFeatures info) {
291             mRecordTvScreenSupport = info.getRecordTvScreenSupport();
292             mOsdStringSupport = info.getSetOsdStringSupport();
293             mDeckControlSupport = info.getDeckControlSupport();
294             mSetAudioRateSupport = info.getSetAudioRateSupport();
295             mArcTxSupport = info.getArcTxSupport();
296             mArcRxSupport = info.getArcRxSupport();
297             mSetAudioVolumeLevelSupport = info.getSetAudioVolumeLevelSupport();
298         }
299 
300         /**
301          * Creates a new {@link DeviceFeatures} object.
302          */
build()303         public DeviceFeatures build() {
304             return new DeviceFeatures(this);
305         }
306 
307         /**
308          * Sets the value for {@link #getRecordTvScreenSupport()}.
309          */
310         @NonNull
setRecordTvScreenSupport(@eatureSupportStatus int recordTvScreenSupport)311         public Builder setRecordTvScreenSupport(@FeatureSupportStatus int recordTvScreenSupport) {
312             mRecordTvScreenSupport = recordTvScreenSupport;
313             return this;
314         }
315 
316         /**
317          * Sets the value for {@link #getSetOsdStringSupport()}.
318          */
319         @NonNull
setSetOsdStringSupport(@eatureSupportStatus int setOsdStringSupport)320         public Builder setSetOsdStringSupport(@FeatureSupportStatus int setOsdStringSupport) {
321             mOsdStringSupport = setOsdStringSupport;
322             return this;
323         }
324 
325         /**
326          * Sets the value for {@link #getDeckControlSupport()}.
327          */
328         @NonNull
setDeckControlSupport(@eatureSupportStatus int deckControlSupport)329         public Builder setDeckControlSupport(@FeatureSupportStatus int deckControlSupport) {
330             mDeckControlSupport = deckControlSupport;
331             return this;
332         }
333 
334         /**
335          * Sets the value for {@link #getSetAudioRateSupport()}.
336          */
337         @NonNull
setSetAudioRateSupport(@eatureSupportStatus int setAudioRateSupport)338         public Builder setSetAudioRateSupport(@FeatureSupportStatus int setAudioRateSupport) {
339             mSetAudioRateSupport = setAudioRateSupport;
340             return this;
341         }
342 
343         /**
344          * Sets the value for {@link #getArcTxSupport()}.
345          */
346         @NonNull
setArcTxSupport(@eatureSupportStatus int arcTxSupport)347         public Builder setArcTxSupport(@FeatureSupportStatus int arcTxSupport) {
348             mArcTxSupport = arcTxSupport;
349             return this;
350         }
351 
352         /**
353          * Sets the value for {@link #getArcRxSupport()}.
354          */
355         @NonNull
setArcRxSupport(@eatureSupportStatus int arcRxSupport)356         public Builder setArcRxSupport(@FeatureSupportStatus int arcRxSupport) {
357             mArcRxSupport = arcRxSupport;
358             return this;
359         }
360 
361         /**
362          * Sets the value for {@link #getSetAudioRateSupport()}.
363          */
364         @NonNull
setSetAudioVolumeLevelSupport( @eatureSupportStatus int setAudioVolumeLevelSupport)365         public Builder setSetAudioVolumeLevelSupport(
366                 @FeatureSupportStatus int setAudioVolumeLevelSupport) {
367             mSetAudioVolumeLevelSupport = setAudioVolumeLevelSupport;
368             return this;
369         }
370 
371         /**
372          * Updates all fields with those in a 'new' instance of {@link DeviceFeatures}.
373          * All fields are replaced with those in the new instance, except when the field is
374          * {@link #FEATURE_SUPPORT_UNKNOWN} in the new instance.
375          */
376         @NonNull
update(DeviceFeatures newDeviceFeatures)377         public Builder update(DeviceFeatures newDeviceFeatures) {
378             mRecordTvScreenSupport = updateFeatureSupportStatus(mRecordTvScreenSupport,
379                     newDeviceFeatures.getRecordTvScreenSupport());
380             mOsdStringSupport = updateFeatureSupportStatus(mOsdStringSupport,
381                     newDeviceFeatures.getSetOsdStringSupport());
382             mDeckControlSupport = updateFeatureSupportStatus(mDeckControlSupport,
383                     newDeviceFeatures.getDeckControlSupport());
384             mSetAudioRateSupport = updateFeatureSupportStatus(mSetAudioRateSupport,
385                     newDeviceFeatures.getSetAudioRateSupport());
386             mArcTxSupport = updateFeatureSupportStatus(mArcTxSupport,
387                     newDeviceFeatures.getArcTxSupport());
388             mArcRxSupport = updateFeatureSupportStatus(mArcRxSupport,
389                     newDeviceFeatures.getArcRxSupport());
390             mSetAudioVolumeLevelSupport = updateFeatureSupportStatus(mSetAudioVolumeLevelSupport,
391                     newDeviceFeatures.getSetAudioVolumeLevelSupport());
392             return this;
393         }
394     }
395 }
396