1 /*
2  * Copyright (C) 2014 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.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 /**
26  * A class to encapsulate device information for HDMI devices including CEC and MHL. In terms of
27  * CEC, this container includes basic information such as logical address, physical address and
28  * device type, and additional information like vendor id and osd name. In terms of MHL device, this
29  * container includes adopter id and device type. Otherwise, it keeps the information of other type
30  * devices for which only port ID, physical address are meaningful.
31  *
32  * @hide
33  */
34 @SystemApi
35 public class HdmiDeviceInfo implements Parcelable {
36 
37     /** TV device type. */
38     public static final int DEVICE_TV = 0;
39 
40     /** Recording device type. */
41     public static final int DEVICE_RECORDER = 1;
42 
43     /** Device type reserved for future usage. */
44     public static final int DEVICE_RESERVED = 2;
45 
46     /** Tuner device type. */
47     public static final int DEVICE_TUNER = 3;
48 
49     /** Playback device type. */
50     public static final int DEVICE_PLAYBACK = 4;
51 
52     /** Audio system device type. */
53     public static final int DEVICE_AUDIO_SYSTEM = 5;
54 
55     /** @hide Pure CEC switch device type. */
56     public static final int DEVICE_PURE_CEC_SWITCH = 6;
57 
58     /** @hide Video processor device type. */
59     public static final int DEVICE_VIDEO_PROCESSOR = 7;
60 
61     // Value indicating the device is not an active source.
62     public static final int DEVICE_INACTIVE = -1;
63 
64     /**
65      * Logical address used to indicate the source comes from internal device. The logical address
66      * of TV(0) is used.
67      */
68     public static final int ADDR_INTERNAL = 0;
69 
70     /**
71      * Physical address used to indicate the source comes from internal device. The physical address
72      * of TV(0) is used.
73      */
74     public static final int PATH_INTERNAL = 0x0000;
75 
76     /** Invalid physical address (routing path) */
77     public static final int PATH_INVALID = 0xFFFF;
78 
79     /** Invalid port ID */
80     public static final int PORT_INVALID = -1;
81 
82     /** Invalid device ID */
83     public static final int ID_INVALID = 0xFFFF;
84 
85     /** Device info used to indicate an inactivated device. */
86     public static final HdmiDeviceInfo INACTIVE_DEVICE = new HdmiDeviceInfo();
87 
88     private static final int HDMI_DEVICE_TYPE_CEC = 0;
89     private static final int HDMI_DEVICE_TYPE_MHL = 1;
90     private static final int HDMI_DEVICE_TYPE_HARDWARE = 2;
91 
92     // Type used to indicate the device that has relinquished its active source status.
93     private static final int HDMI_DEVICE_TYPE_INACTIVE = 100;
94 
95     // Offset used for id value. MHL devices, for instance, will be assigned the value from
96     // ID_OFFSET_MHL.
97     private static final int ID_OFFSET_CEC = 0x0;
98     private static final int ID_OFFSET_MHL = 0x80;
99     private static final int ID_OFFSET_HARDWARE = 0xC0;
100 
101     // Common parameters for all device.
102     private final int mId;
103     private final int mHdmiDeviceType;
104     private final int mPhysicalAddress;
105     private final int mPortId;
106 
107     // CEC only parameters.
108     private final int mLogicalAddress;
109     private final int mDeviceType;
110     private final int mVendorId;
111     private final String mDisplayName;
112     private final int mDevicePowerStatus;
113 
114     // MHL only parameters.
115     private final int mDeviceId;
116     private final int mAdopterId;
117 
118     /**
119      * A helper class to deserialize {@link HdmiDeviceInfo} for a parcel.
120      */
121     public static final @android.annotation.NonNull Parcelable.Creator<HdmiDeviceInfo> CREATOR =
122             new Parcelable.Creator<HdmiDeviceInfo>() {
123                 @Override
124                 public HdmiDeviceInfo createFromParcel(Parcel source) {
125                     int hdmiDeviceType = source.readInt();
126                     int physicalAddress = source.readInt();
127                     int portId = source.readInt();
128 
129                     switch (hdmiDeviceType) {
130                         case HDMI_DEVICE_TYPE_CEC:
131                             int logicalAddress = source.readInt();
132                             int deviceType = source.readInt();
133                             int vendorId = source.readInt();
134                             int powerStatus = source.readInt();
135                             String displayName = source.readString();
136                             return new HdmiDeviceInfo(logicalAddress, physicalAddress, portId,
137                                     deviceType, vendorId, displayName, powerStatus);
138                         case HDMI_DEVICE_TYPE_MHL:
139                             int deviceId = source.readInt();
140                             int adopterId = source.readInt();
141                             return new HdmiDeviceInfo(physicalAddress, portId, adopterId, deviceId);
142                         case HDMI_DEVICE_TYPE_HARDWARE:
143                             return new HdmiDeviceInfo(physicalAddress, portId);
144                         case HDMI_DEVICE_TYPE_INACTIVE:
145                             return HdmiDeviceInfo.INACTIVE_DEVICE;
146                         default:
147                             return null;
148                     }
149                 }
150 
151                 @Override
152                 public HdmiDeviceInfo[] newArray(int size) {
153                     return new HdmiDeviceInfo[size];
154                 }
155             };
156 
157     /**
158      * Constructor. Used to initialize the instance for CEC device.
159      *
160      * @param logicalAddress logical address of HDMI-CEC device
161      * @param physicalAddress physical address of HDMI-CEC device
162      * @param portId HDMI port ID (1 for HDMI1)
163      * @param deviceType type of device
164      * @param vendorId vendor id of device. Used for vendor specific command.
165      * @param displayName name of device
166      * @param powerStatus device power status
167      * @hide
168      */
HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType, int vendorId, String displayName, int powerStatus)169     public HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
170             int vendorId, String displayName, int powerStatus) {
171         mHdmiDeviceType = HDMI_DEVICE_TYPE_CEC;
172         mPhysicalAddress = physicalAddress;
173         mPortId = portId;
174 
175         mId = idForCecDevice(logicalAddress);
176         mLogicalAddress = logicalAddress;
177         mDeviceType = deviceType;
178         mVendorId = vendorId;
179         mDevicePowerStatus = powerStatus;
180         mDisplayName = displayName;
181 
182         mDeviceId = -1;
183         mAdopterId = -1;
184     }
185 
186     /**
187      * Constructor. Used to initialize the instance for CEC device.
188      *
189      * @param logicalAddress logical address of HDMI-CEC device
190      * @param physicalAddress physical address of HDMI-CEC device
191      * @param portId HDMI port ID (1 for HDMI1)
192      * @param deviceType type of device
193      * @param vendorId vendor id of device. Used for vendor specific command.
194      * @param displayName name of device
195      * @hide
196      */
HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType, int vendorId, String displayName)197     public HdmiDeviceInfo(int logicalAddress, int physicalAddress, int portId, int deviceType,
198             int vendorId, String displayName) {
199         this(logicalAddress, physicalAddress, portId, deviceType,
200                 vendorId, displayName, HdmiControlManager.POWER_STATUS_UNKNOWN);
201     }
202 
203     /**
204      * Constructor. Used to initialize the instance for device representing hardware port.
205      *
206      * @param physicalAddress physical address of the port
207      * @param portId HDMI port ID (1 for HDMI1)
208      * @hide
209      */
HdmiDeviceInfo(int physicalAddress, int portId)210     public HdmiDeviceInfo(int physicalAddress, int portId) {
211         mHdmiDeviceType = HDMI_DEVICE_TYPE_HARDWARE;
212         mPhysicalAddress = physicalAddress;
213         mPortId = portId;
214 
215         mId = idForHardware(portId);
216         mLogicalAddress = -1;
217         mDeviceType = DEVICE_RESERVED;
218         mVendorId = 0;
219         mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
220         mDisplayName = "HDMI" + portId;
221 
222         mDeviceId = -1;
223         mAdopterId = -1;
224     }
225 
226     /**
227      * Constructor. Used to initialize the instance for MHL device.
228      *
229      * @param physicalAddress physical address of HDMI device
230      * @param portId portId HDMI port ID (1 for HDMI1)
231      * @param adopterId adopter id of MHL
232      * @param deviceId device id of MHL
233      * @hide
234      */
HdmiDeviceInfo(int physicalAddress, int portId, int adopterId, int deviceId)235     public HdmiDeviceInfo(int physicalAddress, int portId, int adopterId, int deviceId) {
236         mHdmiDeviceType = HDMI_DEVICE_TYPE_MHL;
237         mPhysicalAddress = physicalAddress;
238         mPortId = portId;
239 
240         mId = idForMhlDevice(portId);
241         mLogicalAddress = -1;
242         mDeviceType = DEVICE_RESERVED;
243         mVendorId = 0;
244         mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
245         mDisplayName = "Mobile";
246 
247         mDeviceId = adopterId;
248         mAdopterId = deviceId;
249     }
250 
251     /**
252      * Constructor. Used to initialize the instance representing an inactivated device.
253      * Can be passed input change listener to indicate the active source yielded
254      * its status, hence the listener should take an appropriate action such as
255      * switching to other input.
256      */
HdmiDeviceInfo()257     public HdmiDeviceInfo() {
258         mHdmiDeviceType = HDMI_DEVICE_TYPE_INACTIVE;
259         mPhysicalAddress = PATH_INVALID;
260         mId = ID_INVALID;
261 
262         mLogicalAddress = -1;
263         mDeviceType = DEVICE_INACTIVE;
264         mPortId = PORT_INVALID;
265         mDevicePowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
266         mDisplayName = "Inactive";
267         mVendorId = 0;
268 
269         mDeviceId = -1;
270         mAdopterId = -1;
271     }
272 
273     /**
274      * Returns the id of the device.
275      */
getId()276     public int getId() {
277         return mId;
278     }
279 
280     /**
281      * Returns the id to be used for CEC device.
282      *
283      * @param address logical address of CEC device
284      * @return id for CEC device
285      */
idForCecDevice(int address)286     public static int idForCecDevice(int address) {
287         // The id is generated based on the logical address.
288         return ID_OFFSET_CEC + address;
289     }
290 
291     /**
292      * Returns the id to be used for MHL device.
293      *
294      * @param portId port which the MHL device is connected to
295      * @return id for MHL device
296      */
idForMhlDevice(int portId)297     public static int idForMhlDevice(int portId) {
298         // The id is generated based on the port id since there can be only one MHL device per port.
299         return ID_OFFSET_MHL + portId;
300     }
301 
302     /**
303      * Returns the id to be used for hardware port.
304      *
305      * @param portId port id
306      * @return id for hardware port
307      */
idForHardware(int portId)308     public static int idForHardware(int portId) {
309         return ID_OFFSET_HARDWARE + portId;
310     }
311 
312     /**
313      * Returns the CEC logical address of the device.
314      */
getLogicalAddress()315     public int getLogicalAddress() {
316         return mLogicalAddress;
317     }
318 
319     /**
320      * Returns the physical address of the device.
321      */
getPhysicalAddress()322     public int getPhysicalAddress() {
323         return mPhysicalAddress;
324     }
325 
326     /**
327      * Returns the port ID.
328      */
getPortId()329     public int getPortId() {
330         return mPortId;
331     }
332 
333     /**
334      * Returns CEC type of the device. For more details, refer constants between {@link #DEVICE_TV}
335      * and {@link #DEVICE_INACTIVE}.
336      */
getDeviceType()337     public int getDeviceType() {
338         return mDeviceType;
339     }
340 
341     /**
342      * Returns device's power status. It should be one of the following values.
343      * <ul>
344      * <li>{@link HdmiControlManager#POWER_STATUS_ON}
345      * <li>{@link HdmiControlManager#POWER_STATUS_STANDBY}
346      * <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_ON}
347      * <li>{@link HdmiControlManager#POWER_STATUS_TRANSIENT_TO_STANDBY}
348      * <li>{@link HdmiControlManager#POWER_STATUS_UNKNOWN}
349      * </ul>
350      */
getDevicePowerStatus()351     public int getDevicePowerStatus() {
352         return mDevicePowerStatus;
353     }
354 
355     /**
356      * Returns MHL device id. Return -1 for non-MHL device.
357      */
getDeviceId()358     public int getDeviceId() {
359         return mDeviceId;
360     }
361 
362     /**
363      * Returns MHL adopter id. Return -1 for non-MHL device.
364      */
getAdopterId()365     public int getAdopterId() {
366         return mAdopterId;
367     }
368 
369     /**
370      * Returns {@code true} if the device is of a type that can be an input source.
371      */
isSourceType()372     public boolean isSourceType() {
373         if (isCecDevice()) {
374             return mDeviceType == DEVICE_PLAYBACK
375                     || mDeviceType == DEVICE_RECORDER
376                     || mDeviceType == DEVICE_TUNER;
377         } else if (isMhlDevice()) {
378             return true;
379         } else {
380             return false;
381         }
382     }
383 
384     /**
385      * Returns {@code true} if the device represents an HDMI-CEC device. {@code false} if the device
386      * is either MHL or other device.
387      */
isCecDevice()388     public boolean isCecDevice() {
389         return mHdmiDeviceType == HDMI_DEVICE_TYPE_CEC;
390     }
391 
392     /**
393      * Returns {@code true} if the device represents an MHL device. {@code false} if the device is
394      * either CEC or other device.
395      */
isMhlDevice()396     public boolean isMhlDevice() {
397         return mHdmiDeviceType == HDMI_DEVICE_TYPE_MHL;
398     }
399 
400     /**
401      * Return {@code true} if the device represents an inactivated device that relinquishes
402      * its status as active source by &lt;Active Source&gt; (HDMI-CEC) or Content-off (MHL).
403      */
isInactivated()404     public boolean isInactivated() {
405         return mHdmiDeviceType == HDMI_DEVICE_TYPE_INACTIVE;
406     }
407 
408     /**
409      * Returns display (OSD) name of the device.
410      */
getDisplayName()411     public String getDisplayName() {
412         return mDisplayName;
413     }
414 
415     /**
416      * Returns vendor id of the device. Vendor id is used to distinguish devices built by other
417      * manufactures. This is required for vendor-specific command on CEC standard.
418      */
getVendorId()419     public int getVendorId() {
420         return mVendorId;
421     }
422 
423     /**
424      * Describes the kinds of special objects contained in this Parcelable's marshalled
425      * representation.
426      */
427     @Override
describeContents()428     public int describeContents() {
429         return 0;
430     }
431 
432     /**
433      * Serializes this object into a {@link Parcel}.
434      *
435      * @param dest The Parcel in which the object should be written.
436      * @param flags Additional flags about how the object should be written. May be 0 or
437      *            {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
438      */
439     @Override
writeToParcel(Parcel dest, int flags)440     public void writeToParcel(Parcel dest, int flags) {
441         dest.writeInt(mHdmiDeviceType);
442         dest.writeInt(mPhysicalAddress);
443         dest.writeInt(mPortId);
444         switch (mHdmiDeviceType) {
445             case HDMI_DEVICE_TYPE_CEC:
446                 dest.writeInt(mLogicalAddress);
447                 dest.writeInt(mDeviceType);
448                 dest.writeInt(mVendorId);
449                 dest.writeInt(mDevicePowerStatus);
450                 dest.writeString(mDisplayName);
451                 break;
452             case HDMI_DEVICE_TYPE_MHL:
453                 dest.writeInt(mDeviceId);
454                 dest.writeInt(mAdopterId);
455                 break;
456             case HDMI_DEVICE_TYPE_INACTIVE:
457                 // flow through
458             default:
459                 // no-op
460         }
461     }
462 
463     @NonNull
464     @Override
toString()465     public String toString() {
466         StringBuffer s = new StringBuffer();
467         switch (mHdmiDeviceType) {
468             case HDMI_DEVICE_TYPE_CEC:
469                 s.append("CEC: ");
470                 s.append("logical_address: ").append(String.format("0x%02X", mLogicalAddress));
471                 s.append(" ");
472                 s.append("device_type: ").append(mDeviceType).append(" ");
473                 s.append("vendor_id: ").append(mVendorId).append(" ");
474                 s.append("display_name: ").append(mDisplayName).append(" ");
475                 s.append("power_status: ").append(mDevicePowerStatus).append(" ");
476                 break;
477             case HDMI_DEVICE_TYPE_MHL:
478                 s.append("MHL: ");
479                 s.append("device_id: ").append(String.format("0x%04X", mDeviceId)).append(" ");
480                 s.append("adopter_id: ").append(String.format("0x%04X", mAdopterId)).append(" ");
481                 break;
482 
483             case HDMI_DEVICE_TYPE_HARDWARE:
484                 s.append("Hardware: ");
485                 break;
486             case HDMI_DEVICE_TYPE_INACTIVE:
487                 s.append("Inactivated: ");
488                 break;
489             default:
490                 return "";
491         }
492         s.append("physical_address: ").append(String.format("0x%04X", mPhysicalAddress));
493         s.append(" ");
494         s.append("port_id: ").append(mPortId);
495         return s.toString();
496     }
497 
498     @Override
equals(@ullable Object obj)499     public boolean equals(@Nullable Object obj) {
500         if (!(obj instanceof HdmiDeviceInfo)) {
501             return false;
502         }
503 
504         HdmiDeviceInfo other = (HdmiDeviceInfo) obj;
505         return mHdmiDeviceType == other.mHdmiDeviceType
506                 && mPhysicalAddress == other.mPhysicalAddress
507                 && mPortId == other.mPortId
508                 && mLogicalAddress == other.mLogicalAddress
509                 && mDeviceType == other.mDeviceType
510                 && mVendorId == other.mVendorId
511                 && mDevicePowerStatus == other.mDevicePowerStatus
512                 && mDisplayName.equals(other.mDisplayName)
513                 && mDeviceId == other.mDeviceId
514                 && mAdopterId == other.mAdopterId;
515     }
516 }
517