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