HdmiControlManager.java revision 2e8f1b6399089626b4f0249427626ba6e63a62ef
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.Nullable;
20import android.annotation.SdkConstant;
21import android.annotation.SdkConstant.SdkConstantType;
22import android.annotation.SystemApi;
23import android.os.RemoteException;
24
25/**
26 * The {@link HdmiControlManager} class is used to send HDMI control messages
27 * to attached CEC devices.
28 *
29 * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
30 * hosted in the system. {@link #getTvClient()}, for instance will return an
31 * {@link HdmiTvClient} object if the system is configured to host one. Android system
32 * can host more than one logical CEC devices. If multiple types are configured they
33 * all work as if they were independent logical devices running in the system.
34 *
35 * @hide
36 */
37@SystemApi
38public final class HdmiControlManager {
39    @Nullable private final IHdmiControlService mService;
40
41    /**
42     * Broadcast Action: Display OSD message.
43     * <p>Send when the service has a message to display on screen for events
44     * that need user's attention such as ARC status change.
45     * <p>Always contains the extra fields {@link #EXTRA_MESSAGE_ID}.
46     * <p>Requires {@link android.Manifest.permission#HDMI_CEC} to receive.
47     */
48    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
49    public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
50
51    // --- Messages for ACTION_OSD_MESSAGE ---
52    /**
53     * Message that ARC enabled device is connected to invalid port (non-ARC port).
54     */
55    public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1;
56
57    /**
58     * Message used by TV to receive volume status from Audio Receiver. It should check volume value
59     * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRAM_PARAM1}. If the
60     * value is in range of [0,100], it is current volume of Audio Receiver. And there is another
61     * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute.
62     */
63    public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2;
64
65    /**
66     * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of
67     * the message to display on screen.
68     */
69    public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
70    /**
71     * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value
72     * of the message.
73     */
74    public static final String EXTRA_MESSAGE_EXTRAM_PARAM1 =
75            "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
76
77    /**
78     * Volume value for mute state.
79     */
80    public static final int AVR_VOLUME_MUTED = 101;
81
82    public static final int POWER_STATUS_UNKNOWN = -1;
83    public static final int POWER_STATUS_ON = 0;
84    public static final int POWER_STATUS_STANDBY = 1;
85    public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
86    public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
87
88    public static final int RESULT_SUCCESS = 0;
89    public static final int RESULT_TIMEOUT = 1;
90    public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
91    public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
92    public static final int RESULT_ALREADY_IN_PROGRESS = 4;
93    public static final int RESULT_EXCEPTION = 5;
94    public static final int RESULT_INCORRECT_MODE = 6;
95    public static final int RESULT_COMMUNICATION_FAILED = 7;
96
97    public static final int DEVICE_EVENT_ADD_DEVICE = 1;
98    public static final int DEVICE_EVENT_REMOVE_DEVICE = 2;
99    public static final int DEVICE_EVENT_UPDATE_DEVICE = 3;
100
101    // --- One Touch Recording success result
102    /** Recording currently selected source. Indicates the status of a recording. */
103    public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01;
104    /** Recording Digital Service. Indicates the status of a recording. */
105    public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02;
106    /** Recording Analogue Service. Indicates the status of a recording. */
107    public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03;
108    /** Recording External input. Indicates the status of a recording. */
109    public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04;
110
111    // --- One Touch Record failure result
112    /** No recording – unable to record Digital Service. No suitable tuner. */
113    public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05;
114    /** No recording – unable to record Analogue Service. No suitable tuner. */
115    public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06;
116    /**
117     * No recording – unable to select required service. as suitable tuner, but the requested
118     * parameters are invalid or out of range for that tuner.
119     */
120    public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07;
121    /** No recording – invalid External plug number */
122    public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09;
123    /** No recording – invalid External Physical Address */
124    public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A;
125    /** No recording – CA system not supported */
126    public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B;
127    /** No Recording – No or Insufficient CA Entitlements” */
128    public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C;
129    /** No recording – Not allowed to copy source. Source is “copy never”. */
130    public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D;
131    /** No recording – No further copies allowed */
132    public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E;
133    /** No recording – No media */
134    public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10;
135    /** No recording – playing */
136    public static final int ONE_TOUCH_RECORD_PLAYING = 0x11;
137    /** No recording – already recording */
138    public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12;
139    /** No recording – media protected */
140    public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13;
141    /** No recording – no source signal */
142    public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14;
143    /** No recording – media problem */
144    public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15;
145    /** No recording – not enough space available */
146    public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16;
147    /** No recording – Parental Lock On */
148    public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17;
149    /** Recording terminated normally */
150    public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A;
151    /** Recording has already terminated */
152    public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B;
153    /** No recording – other reason */
154    public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F;
155    // From here extra message for recording that is not mentioned in CEC spec
156    /** No recording. Previous recording request in progress. */
157    public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30;
158    /** No recording. Please check recorder and connection. */
159    public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31;
160    /** Cannot record currently displayed source. */
161    public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32;
162    /** CEC is disabled. */
163    public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33;
164
165    // --- Types for timer recording
166    /** Timer recording type for digital service source. */
167    public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
168    /** Timer recording type for analogue service source. */
169    public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
170    /** Timer recording type for external source. */
171    public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
172
173    // --- Timer Status Data
174    /** [Timer Status Data/Media Info] - Media present and not protected. */
175    public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0x0;
176    /** [Timer Status Data/Media Info] - Media present, but protected. */
177    public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 0x1;
178    /** [Timer Status Data/Media Info] - Media not present. */
179    public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 0x2;
180
181    /** [Timer Status Data/Programmed Info] - Enough space available for recording. */
182    public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 0x8;
183    /** [Timer Status Data/Programmed Info] - Not enough space available for recording. */
184    public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 0x9;
185    /** [Timer Status Data/Programmed Info] - Might not enough space available for recording. */
186    public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 0xB;
187    /** [Timer Status Data/Programmed Info] - No media info available. */
188    public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 0xA;
189
190    /** [Timer Status Data/Not Programmed Error Info] - No free timer available. */
191    public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 0x1;
192    /** [Timer Status Data/Not Programmed Error Info] - Date out of range. */
193    public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 0x2;
194    /** [Timer Status Data/Not Programmed Error Info] - Recording Sequence error. */
195    public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 0x3;
196    /** [Timer Status Data/Not Programmed Error Info] - Invalid External Plug Number. */
197    public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 0x4;
198    /** [Timer Status Data/Not Programmed Error Info] - Invalid External Physical Address. */
199    public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 0x5;
200    /** [Timer Status Data/Not Programmed Error Info] - CA system not supported. */
201    public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 0x6;
202    /** [Timer Status Data/Not Programmed Error Info] - No or insufficient CA Entitlements. */
203    public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 0x7;
204    /** [Timer Status Data/Not Programmed Error Info] - Does not support resolution. */
205    public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 0x8;
206    /** [Timer Status Data/Not Programmed Error Info] - Parental Lock On. */
207    public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON= 0x9;
208    /** [Timer Status Data/Not Programmed Error Info] - Clock Failure. */
209    public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 0xA;
210    /** [Timer Status Data/Not Programmed Error Info] - Duplicate: already programmed. */
211    public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 0xE;
212
213    // --- Extra result value for timer recording.
214    /** No extra error. */
215    public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0x00;
216    /** No timer recording - check recorder and connection. */
217    public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01;
218    /** No timer recording - cannot record selected source. */
219    public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02;
220    /** CEC is disabled. */
221    public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x03;
222
223    // -- Timer cleared status data code used for result of onClearTimerRecordingResult.
224    /** Timer not cleared – recording. */
225    public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0x00;
226    /** Timer not cleared – no matching. */
227    public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 0x01;
228    /** Timer not cleared – no info available. */
229    public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 0x02;
230    /** Timer cleared. */
231    public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 0x80;
232    /** Clear timer error - check recorder and connection. */
233    public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 0xA0;
234    /** Clear timer error - cannot clear timer for selected source. */
235    public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 0xA1;
236    /** Clear timer error - CEC is disabled. */
237    public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
238
239    // True if we have a logical device of type playback hosted in the system.
240    private final boolean mHasPlaybackDevice;
241    // True if we have a logical device of type TV hosted in the system.
242    private final boolean mHasTvDevice;
243
244    /**
245     * @hide - hide this constructor because it has a parameter of type
246     * IHdmiControlService, which is a system private class. The right way
247     * to create an instance of this class is using the factory
248     * Context.getSystemService.
249     */
250    public HdmiControlManager(IHdmiControlService service) {
251        mService = service;
252        int[] types = null;
253        if (mService != null) {
254            try {
255                types = mService.getSupportedTypes();
256            } catch (RemoteException e) {
257                // Do nothing.
258            }
259        }
260        mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
261        mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
262    }
263
264    private static boolean hasDeviceType(int[] types, int type) {
265        if (types == null) {
266            return false;
267        }
268        for (int t : types) {
269            if (t == type) {
270                return true;
271            }
272        }
273        return false;
274    }
275
276    /**
277     * Gets an object that represents an HDMI-CEC logical device of a specified type.
278     *
279     * @param type CEC device type
280     * @return {@link HdmiClient} instance. {@code null} on failure.
281     * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
282     * See {@link HdmiDeviceInfo#DEVICE_TV}
283     */
284    @Nullable
285    public HdmiClient getClient(int type) {
286        if (mService == null) {
287            return null;
288        }
289        switch (type) {
290            case HdmiDeviceInfo.DEVICE_TV:
291                return mHasTvDevice ? new HdmiTvClient(mService) : null;
292            case HdmiDeviceInfo.DEVICE_PLAYBACK:
293                return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
294            default:
295                return null;
296        }
297    }
298
299    /**
300     * Gets an object that represents an HDMI-CEC logical device of type playback on the system.
301     *
302     * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
303     * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
304     * system if the system is configured to host more than one type of HDMI-CEC logical devices.
305     *
306     * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
307     */
308    @Nullable
309    public HdmiPlaybackClient getPlaybackClient() {
310        return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
311    }
312
313    /**
314     * Gets an object that represents an HDMI-CEC logical device of type TV on the system.
315     *
316     * <p>Used to send HDMI control messages to other devices and manage them through
317     * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
318     * system if the system is configured to host more than one type of HDMI-CEC logical devices.
319     *
320     * @return {@link HdmiTvClient} instance. {@code null} on failure.
321     */
322    @Nullable
323    public HdmiTvClient getTvClient() {
324        return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
325    }
326
327    /**
328     * Listener used to get hotplug event from HDMI port.
329     */
330    public interface HotplugEventListener {
331        void onReceived(HdmiHotplugEvent event);
332    }
333
334    /**
335     * Listener used to get vendor-specific commands.
336     */
337    public interface VendorCommandListener {
338        /**
339         * Called when a vendor command is received.
340         *
341         * @param srcAddress source logical address
342         * @param params vendor-specific parameters
343         * @param hasVendorId {@code true} if the command is &lt;Vendor Command
344         *        With ID&gt;. The first 3 bytes of params is vendor id.
345         */
346        void onReceived(int srcAddress, byte[] params, boolean hasVendorId);
347    }
348
349    /**
350     * Adds a listener to get informed of {@link HdmiHotplugEvent}.
351     *
352     * <p>To stop getting the notification,
353     * use {@link #removeHotplugEventListener(HotplugEventListener)}.
354     *
355     * @param listener {@link HotplugEventListener} instance
356     * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
357     */
358    public void addHotplugEventListener(HotplugEventListener listener) {
359        if (mService == null) {
360            return;
361        }
362        try {
363            mService.addHotplugEventListener(getHotplugEventListenerWrapper(listener));
364        } catch (RemoteException e) {
365            // Do nothing.
366        }
367    }
368
369    /**
370     * Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
371     *
372     * @param listener {@link HotplugEventListener} instance to be removed
373     */
374    public void removeHotplugEventListener(HotplugEventListener listener) {
375        if (mService == null) {
376            return;
377        }
378        try {
379            mService.removeHotplugEventListener(getHotplugEventListenerWrapper(listener));
380        } catch (RemoteException e) {
381            // Do nothing.
382        }
383    }
384
385    private IHdmiHotplugEventListener getHotplugEventListenerWrapper(
386            final HotplugEventListener listener) {
387        return new IHdmiHotplugEventListener.Stub() {
388            @Override
389            public void onReceived(HdmiHotplugEvent event) {
390                listener.onReceived(event);;
391            }
392        };
393    }
394}
395