blob: b520d2c14edc0135ea83f02e0a5713114a65ef37 [file] [log] [blame]
Jinsuk Kim91120c52014-05-08 17:12:51 +09001/*
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;
Jeff Sharkey98af2e42018-02-16 10:14:57 -070020import android.annotation.RequiresFeature;
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -060021import android.annotation.RequiresPermission;
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -060024import android.annotation.SuppressLint;
Jinsuk Kim66d1eb22014-06-06 16:12:18 +090025import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060026import android.annotation.SystemService;
Shubang67373192018-06-08 18:30:15 -070027import android.content.Context;
28import android.content.pm.PackageManager;
Jinsuk Kim78d695d2014-05-13 16:36:15 +090029import android.os.RemoteException;
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +090030import android.util.ArrayMap;
31import android.util.Log;
Jinsuk Kim78d695d2014-05-13 16:36:15 +090032
Jinsuk Kim91120c52014-05-08 17:12:51 +090033/**
34 * The {@link HdmiControlManager} class is used to send HDMI control messages
35 * to attached CEC devices.
36 *
37 * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
38 * hosted in the system. {@link #getTvClient()}, for instance will return an
39 * {@link HdmiTvClient} object if the system is configured to host one. Android system
40 * can host more than one logical CEC devices. If multiple types are configured they
41 * all work as if they were independent logical devices running in the system.
Jinsuk Kim66d1eb22014-06-06 16:12:18 +090042 *
43 * @hide
Jinsuk Kim91120c52014-05-08 17:12:51 +090044 */
Jinsuk Kim66d1eb22014-06-06 16:12:18 +090045@SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060046@SystemService(Context.HDMI_CONTROL_SERVICE)
Jeff Sharkey98af2e42018-02-16 10:14:57 -070047@RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
Jinsuk Kim91120c52014-05-08 17:12:51 +090048public final class HdmiControlManager {
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +090049 private static final String TAG = "HdmiControlManager";
50
Jinsuk Kim91120c52014-05-08 17:12:51 +090051 @Nullable private final IHdmiControlService mService;
52
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090053 /**
54 * Broadcast Action: Display OSD message.
55 * <p>Send when the service has a message to display on screen for events
56 * that need user's attention such as ARC status change.
Jungshik Jange5a93372014-07-25 13:41:14 +090057 * <p>Always contains the extra fields {@link #EXTRA_MESSAGE_ID}.
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090058 * <p>Requires {@link android.Manifest.permission#HDMI_CEC} to receive.
59 */
60 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
61 public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
62
Jungshik Jang339227d2014-08-25 15:37:20 +090063 // --- Messages for ACTION_OSD_MESSAGE ---
64 /**
65 * Message that ARC enabled device is connected to invalid port (non-ARC port).
66 */
67 public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1;
68
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090069 /**
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090070 * Message used by TV to receive volume status from Audio Receiver. It should check volume value
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +090071 * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRA_PARAM1}. If the
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090072 * value is in range of [0,100], it is current volume of Audio Receiver. And there is another
73 * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute.
74 */
75 public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2;
76
77 /**
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090078 * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of
79 * the message to display on screen.
80 */
81 public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090082 /**
83 * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value
84 * of the message.
85 */
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +090086 public static final String EXTRA_MESSAGE_EXTRA_PARAM1 =
Jungshik Jang2e8f1b62014-09-03 08:28:02 +090087 "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
88
89 /**
90 * Volume value for mute state.
91 */
92 public static final int AVR_VOLUME_MUTED = 101;
Jinsuk Kimc7eba0f2014-07-07 14:18:02 +090093
Jinsuk Kimc0c20d02014-07-04 14:34:31 +090094 public static final int POWER_STATUS_UNKNOWN = -1;
95 public static final int POWER_STATUS_ON = 0;
96 public static final int POWER_STATUS_STANDBY = 1;
97 public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
98 public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
99
100 public static final int RESULT_SUCCESS = 0;
101 public static final int RESULT_TIMEOUT = 1;
102 public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
103 public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
Jinsuk Kimcb802872015-10-13 08:22:09 +0900104
105 @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4;
Jinsuk Kimc0c20d02014-07-04 14:34:31 +0900106 public static final int RESULT_EXCEPTION = 5;
107 public static final int RESULT_INCORRECT_MODE = 6;
Jinsuk Kimb38cd682014-07-07 08:05:03 +0900108 public static final int RESULT_COMMUNICATION_FAILED = 7;
Jinsuk Kimc0c20d02014-07-04 14:34:31 +0900109
Jungshik Jang61daf6b2014-08-08 11:38:28 +0900110 public static final int DEVICE_EVENT_ADD_DEVICE = 1;
111 public static final int DEVICE_EVENT_REMOVE_DEVICE = 2;
112 public static final int DEVICE_EVENT_UPDATE_DEVICE = 3;
113
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900114 // --- One Touch Recording success result
Jungshik Jangb6591b82014-07-23 16:10:23 +0900115 /** Recording currently selected source. Indicates the status of a recording. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900116 public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900117 /** Recording Digital Service. Indicates the status of a recording. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900118 public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900119 /** Recording Analogue Service. Indicates the status of a recording. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900120 public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900121 /** Recording External input. Indicates the status of a recording. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900122 public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04;
123
124 // --- One Touch Record failure result
Jungshik Jangb6591b82014-07-23 16:10:23 +0900125 /** No recording – unable to record Digital Service. No suitable tuner. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900126 public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900127 /** No recording – unable to record Analogue Service. No suitable tuner. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900128 public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900129 /**
130 * No recording – unable to select required service. as suitable tuner, but the requested
131 * parameters are invalid or out of range for that tuner.
132 */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900133 public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900134 /** No recording – invalid External plug number */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900135 public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900136 /** No recording – invalid External Physical Address */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900137 public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900138 /** No recording – CA system not supported */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900139 public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900140 /** No Recording – No or Insufficient CA Entitlements” */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900141 public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900142 /** No recording – Not allowed to copy source. Source is “copy never”. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900143 public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900144 /** No recording – No further copies allowed */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900145 public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900146 /** No recording – No media */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900147 public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900148 /** No recording – playing */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900149 public static final int ONE_TOUCH_RECORD_PLAYING = 0x11;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900150 /** No recording – already recording */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900151 public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900152 /** No recording – media protected */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900153 public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900154 /** No recording – no source signal */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900155 public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900156 /** No recording – media problem */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900157 public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900158 /** No recording – not enough space available */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900159 public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900160 /** No recording – Parental Lock On */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900161 public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900162 /** Recording terminated normally */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900163 public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900164 /** Recording has already terminated */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900165 public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900166 /** No recording – other reason */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900167 public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900168 // From here extra message for recording that is not mentioned in CEC spec
169 /** No recording. Previous recording request in progress. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900170 public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900171 /** No recording. Please check recorder and connection. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900172 public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900173 /** Cannot record currently displayed source. */
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900174 public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32;
175 /** CEC is disabled. */
176 public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33;
Jungshik Jangb6591b82014-07-23 16:10:23 +0900177
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900178 // --- Types for timer recording
Jungshik Jangb6591b82014-07-23 16:10:23 +0900179 /** Timer recording type for digital service source. */
180 public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
181 /** Timer recording type for analogue service source. */
182 public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
183 /** Timer recording type for external source. */
184 public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
185
Jungshik Jange5a93372014-07-25 13:41:14 +0900186 // --- Timer Status Data
187 /** [Timer Status Data/Media Info] - Media present and not protected. */
188 public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0x0;
189 /** [Timer Status Data/Media Info] - Media present, but protected. */
190 public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 0x1;
191 /** [Timer Status Data/Media Info] - Media not present. */
192 public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 0x2;
193
194 /** [Timer Status Data/Programmed Info] - Enough space available for recording. */
195 public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 0x8;
196 /** [Timer Status Data/Programmed Info] - Not enough space available for recording. */
197 public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 0x9;
198 /** [Timer Status Data/Programmed Info] - Might not enough space available for recording. */
199 public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 0xB;
200 /** [Timer Status Data/Programmed Info] - No media info available. */
201 public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 0xA;
202
203 /** [Timer Status Data/Not Programmed Error Info] - No free timer available. */
204 public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 0x1;
205 /** [Timer Status Data/Not Programmed Error Info] - Date out of range. */
206 public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 0x2;
207 /** [Timer Status Data/Not Programmed Error Info] - Recording Sequence error. */
208 public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 0x3;
209 /** [Timer Status Data/Not Programmed Error Info] - Invalid External Plug Number. */
210 public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 0x4;
211 /** [Timer Status Data/Not Programmed Error Info] - Invalid External Physical Address. */
212 public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 0x5;
213 /** [Timer Status Data/Not Programmed Error Info] - CA system not supported. */
214 public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 0x6;
215 /** [Timer Status Data/Not Programmed Error Info] - No or insufficient CA Entitlements. */
216 public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 0x7;
217 /** [Timer Status Data/Not Programmed Error Info] - Does not support resolution. */
218 public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 0x8;
219 /** [Timer Status Data/Not Programmed Error Info] - Parental Lock On. */
220 public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON= 0x9;
221 /** [Timer Status Data/Not Programmed Error Info] - Clock Failure. */
222 public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 0xA;
223 /** [Timer Status Data/Not Programmed Error Info] - Duplicate: already programmed. */
224 public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 0xE;
225
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900226 // --- Extra result value for timer recording.
Jungshik Jange5a93372014-07-25 13:41:14 +0900227 /** No extra error. */
228 public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0x00;
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900229 /** No timer recording - check recorder and connection. */
Jungshik Jange5a93372014-07-25 13:41:14 +0900230 public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01;
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900231 /** No timer recording - cannot record selected source. */
Jungshik Jange5a93372014-07-25 13:41:14 +0900232 public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02;
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900233 /** CEC is disabled. */
Jungshik Jange5a93372014-07-25 13:41:14 +0900234 public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x03;
235
236 // -- Timer cleared status data code used for result of onClearTimerRecordingResult.
237 /** Timer not cleared – recording. */
238 public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0x00;
239 /** Timer not cleared – no matching. */
240 public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 0x01;
241 /** Timer not cleared – no info available. */
242 public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 0x02;
243 /** Timer cleared. */
244 public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 0x80;
245 /** Clear timer error - check recorder and connection. */
246 public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 0xA0;
247 /** Clear timer error - cannot clear timer for selected source. */
248 public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 0xA1;
249 /** Clear timer error - CEC is disabled. */
250 public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
Jungshik Jang12e5dce2014-07-24 15:27:44 +0900251
Yuncheol Heo0608b932014-10-13 16:39:18 +0900252 /** The HdmiControlService is started. */
253 public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
254 /** The state of HdmiControlService is changed by changing of settings. */
255 public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
256 /** The HdmiControlService is enabled to wake up. */
257 public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
258 /** The HdmiControlService will be disabled to standby. */
259 public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
260
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900261 // True if we have a logical device of type playback hosted in the system.
262 private final boolean mHasPlaybackDevice;
263 // True if we have a logical device of type TV hosted in the system.
264 private final boolean mHasTvDevice;
Shubang67373192018-06-08 18:30:15 -0700265 // True if we have a logical device of type audio system hosted in the system.
266 private final boolean mHasAudioSystemDevice;
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900267
Jinsuk Kim91120c52014-05-08 17:12:51 +0900268 /**
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900269 * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService,
270 * which is a system private class. The right way to create an instance of this class is
271 * using the factory Context.getSystemService.
Jinsuk Kim91120c52014-05-08 17:12:51 +0900272 */
273 public HdmiControlManager(IHdmiControlService service) {
274 mService = service;
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900275 int[] types = null;
276 if (mService != null) {
277 try {
278 types = mService.getSupportedTypes();
279 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700280 throw e.rethrowFromSystemServer();
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900281 }
282 }
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900283 mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
284 mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
Shubang67373192018-06-08 18:30:15 -0700285 mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900286 }
287
288 private static boolean hasDeviceType(int[] types, int type) {
289 if (types == null) {
290 return false;
291 }
292 for (int t : types) {
293 if (t == type) {
294 return true;
295 }
296 }
297 return false;
Jinsuk Kim91120c52014-05-08 17:12:51 +0900298 }
299
300 /**
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900301 * Gets an object that represents an HDMI-CEC logical device of a specified type.
302 *
303 * @param type CEC device type
304 * @return {@link HdmiClient} instance. {@code null} on failure.
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900305 * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
306 * See {@link HdmiDeviceInfo#DEVICE_TV}
Shubang67373192018-06-08 18:30:15 -0700307 * See {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900308 */
309 @Nullable
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600310 @SuppressLint("Doclava125")
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900311 public HdmiClient getClient(int type) {
312 if (mService == null) {
313 return null;
314 }
315 switch (type) {
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900316 case HdmiDeviceInfo.DEVICE_TV:
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900317 return mHasTvDevice ? new HdmiTvClient(mService) : null;
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900318 case HdmiDeviceInfo.DEVICE_PLAYBACK:
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900319 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
Shubang67373192018-06-08 18:30:15 -0700320 case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
321 return mHasAudioSystemDevice ? new HdmiAudioSystemClient(mService) : null;
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900322 default:
323 return null;
324 }
325 }
326
327 /**
328 * Gets an object that represents an HDMI-CEC logical device of type playback on the system.
Jinsuk Kim91120c52014-05-08 17:12:51 +0900329 *
330 * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
331 * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
332 * system if the system is configured to host more than one type of HDMI-CEC logical devices.
333 *
334 * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
335 */
336 @Nullable
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600337 @SuppressLint("Doclava125")
Jinsuk Kim91120c52014-05-08 17:12:51 +0900338 public HdmiPlaybackClient getPlaybackClient() {
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900339 return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
Jinsuk Kim91120c52014-05-08 17:12:51 +0900340 }
341
342 /**
Jinsuk Kim6ffb0382014-08-01 19:13:53 +0900343 * Gets an object that represents an HDMI-CEC logical device of type TV on the system.
Jinsuk Kim91120c52014-05-08 17:12:51 +0900344 *
345 * <p>Used to send HDMI control messages to other devices and manage them through
346 * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
347 * system if the system is configured to host more than one type of HDMI-CEC logical devices.
348 *
349 * @return {@link HdmiTvClient} instance. {@code null} on failure.
350 */
351 @Nullable
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600352 @SuppressLint("Doclava125")
Jinsuk Kim91120c52014-05-08 17:12:51 +0900353 public HdmiTvClient getTvClient() {
Jungshik Jang61f4fbd2014-08-06 19:21:12 +0900354 return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
Jinsuk Kim91120c52014-05-08 17:12:51 +0900355 }
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900356
357 /**
Shubang67373192018-06-08 18:30:15 -0700358 * Gets an object that represents an HDMI-CEC logical device of type audio system on the system.
359 *
360 * <p>Used to send HDMI control messages to other devices like TV through HDMI bus. It is also
361 * possible to communicate with other logical devices hosted in the same system if the system is
362 * configured to host more than one type of HDMI-CEC logical devices.
363 *
364 * @return {@link HdmiAudioSystemClient} instance. {@code null} on failure.
365 *
366 * TODO(b/110094868): unhide for Q
367 * @hide
368 */
369 @Nullable
370 @SuppressLint("Doclava125")
371 public HdmiAudioSystemClient getAudioSystemClient() {
372 return (HdmiAudioSystemClient) getClient(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
373 }
374
375 /**
Donghyun Chob3515642017-03-02 13:47:40 +0900376 * Controls standby mode of the system. It will also try to turn on/off the connected devices if
377 * necessary.
378 *
379 * @param isStandbyModeOn target status of the system's standby mode
380 */
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600381 @RequiresPermission(android.Manifest.permission.HDMI_CEC)
Donghyun Chob3515642017-03-02 13:47:40 +0900382 public void setStandbyMode(boolean isStandbyModeOn) {
383 try {
384 mService.setStandbyMode(isStandbyModeOn);
385 } catch (RemoteException e) {
386 throw e.rethrowFromSystemServer();
387 }
388 }
389
390 /**
Shubang Lu00b976a2018-08-01 18:11:46 -0700391 * Gets whether the system is in system audio mode.
392 *
393 * @hide
394 */
395 public boolean getSystemAudioMode() {
396 try {
397 return mService.getSystemAudioMode();
398 } catch (RemoteException e) {
399 throw e.rethrowFromSystemServer();
400 }
401 }
402
403 /**
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900404 * Listener used to get hotplug event from HDMI port.
405 */
406 public interface HotplugEventListener {
407 void onReceived(HdmiHotplugEvent event);
408 }
409
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900410 private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener>
411 mHotplugEventListeners = new ArrayMap<>();
412
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900413 /**
Jinsuk Kim119160a2014-07-07 18:48:10 +0900414 * Listener used to get vendor-specific commands.
415 */
416 public interface VendorCommandListener {
417 /**
418 * Called when a vendor command is received.
419 *
420 * @param srcAddress source logical address
Yuncheol Heo0608b932014-10-13 16:39:18 +0900421 * @param destAddress destination logical address
Jinsuk Kim119160a2014-07-07 18:48:10 +0900422 * @param params vendor-specific parameters
423 * @param hasVendorId {@code true} if the command is &lt;Vendor Command
424 * With ID&gt;. The first 3 bytes of params is vendor id.
425 */
Yuncheol Heo0608b932014-10-13 16:39:18 +0900426 void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
427
428 /**
429 * The callback is called:
430 * <ul>
431 * <li> before HdmiControlService is disabled.
432 * <li> after HdmiControlService is enabled and the local address is assigned.
433 * </ul>
434 * The client shouldn't hold the thread too long since this is a blocking call.
435 *
436 * @param enabled {@code true} if HdmiControlService is enabled.
437 * @param reason the reason code why the state of HdmiControlService is changed.
438 * @see #CONTROL_STATE_CHANGED_REASON_START
439 * @see #CONTROL_STATE_CHANGED_REASON_SETTING
440 * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
441 * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
442 */
443 void onControlStateChanged(boolean enabled, int reason);
Jinsuk Kim119160a2014-07-07 18:48:10 +0900444 }
445
446 /**
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900447 * Adds a listener to get informed of {@link HdmiHotplugEvent}.
448 *
449 * <p>To stop getting the notification,
Jinsuk Kim9302a732014-05-22 13:24:55 +0900450 * use {@link #removeHotplugEventListener(HotplugEventListener)}.
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900451 *
452 * @param listener {@link HotplugEventListener} instance
Jinsuk Kim9302a732014-05-22 13:24:55 +0900453 * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900454 */
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600455 @RequiresPermission(android.Manifest.permission.HDMI_CEC)
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900456 public void addHotplugEventListener(HotplugEventListener listener) {
457 if (mService == null) {
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900458 Log.e(TAG, "HdmiControlService is not available");
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900459 return;
460 }
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900461 if (mHotplugEventListeners.containsKey(listener)) {
462 Log.e(TAG, "listener is already registered");
463 return;
464 }
465 IHdmiHotplugEventListener wrappedListener = getHotplugEventListenerWrapper(listener);
466 mHotplugEventListeners.put(listener, wrappedListener);
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900467 try {
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900468 mService.addHotplugEventListener(wrappedListener);
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900469 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700470 throw e.rethrowFromSystemServer();
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900471 }
472 }
473
474 /**
475 * Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
476 *
477 * @param listener {@link HotplugEventListener} instance to be removed
478 */
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -0600479 @RequiresPermission(android.Manifest.permission.HDMI_CEC)
Jinsuk Kim9302a732014-05-22 13:24:55 +0900480 public void removeHotplugEventListener(HotplugEventListener listener) {
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900481 if (mService == null) {
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900482 Log.e(TAG, "HdmiControlService is not available");
483 return;
484 }
485 IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener);
486 if (wrappedListener == null) {
487 Log.e(TAG, "tried to remove not-registered listener");
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900488 return;
489 }
490 try {
Yuncheol Heo2b0da5c2014-10-22 14:32:27 +0900491 mService.removeHotplugEventListener(wrappedListener);
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900492 } catch (RemoteException e) {
Jeff Sharkeyc53962d2016-03-01 19:27:23 -0700493 throw e.rethrowFromSystemServer();
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900494 }
495 }
496
497 private IHdmiHotplugEventListener getHotplugEventListenerWrapper(
498 final HotplugEventListener listener) {
499 return new IHdmiHotplugEventListener.Stub() {
Jungshik Jange5a93372014-07-25 13:41:14 +0900500 @Override
Jinsuk Kim78d695d2014-05-13 16:36:15 +0900501 public void onReceived(HdmiHotplugEvent event) {
502 listener.onReceived(event);;
503 }
504 };
505 }
Jinsuk Kim91120c52014-05-08 17:12:51 +0900506}