• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresFeature;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SdkConstant;
26 import android.annotation.SdkConstant.SdkConstantType;
27 import android.annotation.StringDef;
28 import android.annotation.SuppressLint;
29 import android.annotation.SystemApi;
30 import android.annotation.SystemService;
31 import android.content.Context;
32 import android.content.pm.PackageManager;
33 import android.os.Binder;
34 import android.os.RemoteException;
35 import android.sysprop.HdmiProperties;
36 import android.util.ArrayMap;
37 import android.util.Log;
38 
39 import com.android.internal.util.ConcurrentUtils;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.util.Arrays;
44 import java.util.List;
45 import java.util.Objects;
46 import java.util.concurrent.Executor;
47 import java.util.stream.Collectors;
48 
49 /**
50  * The {@link HdmiControlManager} class is used to send HDMI control messages
51  * to attached CEC devices.
52  *
53  * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
54  * hosted in the system. {@link #getTvClient()}, for instance will return an
55  * {@link HdmiTvClient} object if the system is configured to host one. Android system
56  * can host more than one logical CEC devices. If multiple types are configured they
57  * all work as if they were independent logical devices running in the system.
58  *
59  * @hide
60  */
61 @SystemApi
62 @SystemService(Context.HDMI_CONTROL_SERVICE)
63 @RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
64 public final class HdmiControlManager {
65     private static final String TAG = "HdmiControlManager";
66 
67     @Nullable private final IHdmiControlService mService;
68 
69     private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
70 
71     /**
72      * Broadcast Action: Display OSD message.
73      * <p>Send when the service has a message to display on screen for events
74      * that need user's attention such as ARC status change.
75      * <p>Always contains the extra fields {@link #EXTRA_MESSAGE_ID}.
76      * <p>Requires {@link android.Manifest.permission#HDMI_CEC} to receive.
77      */
78     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
79     public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
80 
81     // --- Messages for ACTION_OSD_MESSAGE ---
82     /**
83      * Message that ARC enabled device is connected to invalid port (non-ARC port).
84      */
85     public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1;
86 
87     /**
88      * Message used by TV to receive volume status from Audio Receiver. It should check volume value
89      * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRA_PARAM1}. If the
90      * value is in range of [0,100], it is current volume of Audio Receiver. And there is another
91      * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute.
92      */
93     public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2;
94 
95     /**
96      * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of
97      * the message to display on screen.
98      */
99     public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
100     /**
101      * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value
102      * of the message.
103      */
104     public static final String EXTRA_MESSAGE_EXTRA_PARAM1 =
105             "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
106 
107     /**
108      * Used as an extra field in the Set Menu Language intent. Contains the requested locale.
109      * @hide
110      */
111     public static final String EXTRA_LOCALE = "android.hardware.hdmi.extra.LOCALE";
112 
113     /**
114      * Volume value for mute state.
115      */
116     public static final int AVR_VOLUME_MUTED = 101;
117 
118     public static final int POWER_STATUS_UNKNOWN = -1;
119     public static final int POWER_STATUS_ON = 0;
120     public static final int POWER_STATUS_STANDBY = 1;
121     public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
122     public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
123 
124     @IntDef ({
125         RESULT_SUCCESS,
126         RESULT_TIMEOUT,
127         RESULT_SOURCE_NOT_AVAILABLE,
128         RESULT_TARGET_NOT_AVAILABLE,
129         RESULT_ALREADY_IN_PROGRESS,
130         RESULT_EXCEPTION,
131         RESULT_INCORRECT_MODE,
132         RESULT_COMMUNICATION_FAILED,
133     })
134     public @interface ControlCallbackResult {}
135 
136     /** Control operation is successfully handled by the framework. */
137     public static final int RESULT_SUCCESS = 0;
138     public static final int RESULT_TIMEOUT = 1;
139     /** Source device that the application is using is not available. */
140     public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
141     /** Target device that the application is controlling is not available. */
142     public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
143 
144     @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4;
145     public static final int RESULT_EXCEPTION = 5;
146     public static final int RESULT_INCORRECT_MODE = 6;
147     public static final int RESULT_COMMUNICATION_FAILED = 7;
148 
149     public static final int DEVICE_EVENT_ADD_DEVICE = 1;
150     public static final int DEVICE_EVENT_REMOVE_DEVICE = 2;
151     public static final int DEVICE_EVENT_UPDATE_DEVICE = 3;
152 
153     // --- One Touch Recording success result
154     /** Recording currently selected source. Indicates the status of a recording. */
155     public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01;
156     /** Recording Digital Service. Indicates the status of a recording. */
157     public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02;
158     /** Recording Analogue Service. Indicates the status of a recording. */
159     public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03;
160     /** Recording External input. Indicates the status of a recording. */
161     public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04;
162 
163     // --- One Touch Record failure result
164     /** No recording – unable to record Digital Service. No suitable tuner. */
165     public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05;
166     /** No recording – unable to record Analogue Service. No suitable tuner. */
167     public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06;
168     /**
169      * No recording – unable to select required service. as suitable tuner, but the requested
170      * parameters are invalid or out of range for that tuner.
171      */
172     public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07;
173     /** No recording – invalid External plug number */
174     public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09;
175     /** No recording – invalid External Physical Address */
176     public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A;
177     /** No recording – CA system not supported */
178     public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B;
179     /** No Recording – No or Insufficient CA Entitlements” */
180     public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C;
181     /** No recording – Not allowed to copy source. Source is “copy never”. */
182     public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D;
183     /** No recording – No further copies allowed */
184     public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E;
185     /** No recording – No media */
186     public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10;
187     /** No recording – playing */
188     public static final int ONE_TOUCH_RECORD_PLAYING = 0x11;
189     /** No recording – already recording */
190     public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12;
191     /** No recording – media protected */
192     public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13;
193     /** No recording – no source signal */
194     public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14;
195     /** No recording – media problem */
196     public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15;
197     /** No recording – not enough space available */
198     public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16;
199     /** No recording – Parental Lock On */
200     public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17;
201     /** Recording terminated normally */
202     public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A;
203     /** Recording has already terminated */
204     public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B;
205     /** No recording – other reason */
206     public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F;
207     // From here extra message for recording that is not mentioned in CEC spec
208     /** No recording. Previous recording request in progress. */
209     public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30;
210     /** No recording. Please check recorder and connection. */
211     public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31;
212     /** Cannot record currently displayed source. */
213     public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32;
214     /** CEC is disabled. */
215     public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33;
216 
217     // --- Types for timer recording
218     /** Timer recording type for digital service source. */
219     public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
220     /** Timer recording type for analogue service source. */
221     public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
222     /** Timer recording type for external source. */
223     public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
224 
225     // --- Timer Status Data
226     /** [Timer Status Data/Media Info] - Media present and not protected. */
227     public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0x0;
228     /** [Timer Status Data/Media Info] - Media present, but protected. */
229     public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 0x1;
230     /** [Timer Status Data/Media Info] - Media not present. */
231     public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 0x2;
232 
233     /** [Timer Status Data/Programmed Info] - Enough space available for recording. */
234     public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 0x8;
235     /** [Timer Status Data/Programmed Info] - Not enough space available for recording. */
236     public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 0x9;
237     /** [Timer Status Data/Programmed Info] - Might not enough space available for recording. */
238     public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 0xB;
239     /** [Timer Status Data/Programmed Info] - No media info available. */
240     public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 0xA;
241 
242     /** [Timer Status Data/Not Programmed Error Info] - No free timer available. */
243     public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 0x1;
244     /** [Timer Status Data/Not Programmed Error Info] - Date out of range. */
245     public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 0x2;
246     /** [Timer Status Data/Not Programmed Error Info] - Recording Sequence error. */
247     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 0x3;
248     /** [Timer Status Data/Not Programmed Error Info] - Invalid External Plug Number. */
249     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 0x4;
250     /** [Timer Status Data/Not Programmed Error Info] - Invalid External Physical Address. */
251     public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 0x5;
252     /** [Timer Status Data/Not Programmed Error Info] - CA system not supported. */
253     public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 0x6;
254     /** [Timer Status Data/Not Programmed Error Info] - No or insufficient CA Entitlements. */
255     public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 0x7;
256     /** [Timer Status Data/Not Programmed Error Info] - Does not support resolution. */
257     public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 0x8;
258     /** [Timer Status Data/Not Programmed Error Info] - Parental Lock On. */
259     public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON= 0x9;
260     /** [Timer Status Data/Not Programmed Error Info] - Clock Failure. */
261     public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 0xA;
262     /** [Timer Status Data/Not Programmed Error Info] - Duplicate: already programmed. */
263     public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 0xE;
264 
265     // --- Extra result value for timer recording.
266     /** No extra error. */
267     public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0x00;
268     /** No timer recording - check recorder and connection. */
269     public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01;
270     /** No timer recording - cannot record selected source. */
271     public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02;
272     /** CEC is disabled. */
273     public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x03;
274 
275     // -- Timer cleared status data code used for result of onClearTimerRecordingResult.
276     /** Timer not cleared – recording. */
277     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0x00;
278     /** Timer not cleared – no matching. */
279     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 0x01;
280     /** Timer not cleared – no info available. */
281     public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 0x02;
282     /** Timer cleared. */
283     public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 0x80;
284     /** Clear timer error - check recorder and connection. */
285     public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 0xA0;
286     /** Clear timer error - cannot clear timer for selected source. */
287     public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 0xA1;
288     /** Clear timer error - CEC is disabled. */
289     public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
290 
291     /** The HdmiControlService is started. */
292     public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
293     /** The state of HdmiControlService is changed by changing of settings. */
294     public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
295     /** The HdmiControlService is enabled to wake up. */
296     public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
297     /** The HdmiControlService will be disabled to standby. */
298     public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
299 
300     // -- Whether the HDMI CEC is enabled or disabled.
301     /**
302      * HDMI CEC enabled.
303      *
304      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED
305      */
306     public static final int HDMI_CEC_CONTROL_ENABLED = 1;
307     /**
308      * HDMI CEC disabled.
309      *
310      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED
311      */
312     public static final int HDMI_CEC_CONTROL_DISABLED = 0;
313     /**
314      * @hide
315      *
316      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED
317      */
318     @IntDef(prefix = { "HDMI_CEC_CONTROL_" }, value = {
319             HDMI_CEC_CONTROL_ENABLED,
320             HDMI_CEC_CONTROL_DISABLED
321     })
322     @Retention(RetentionPolicy.SOURCE)
323     public @interface HdmiCecControl {}
324 
325     // -- Supported HDMI-CEC versions.
326     /**
327      * Version constant for HDMI-CEC v1.4b.
328      *
329      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION
330      */
331     public static final int HDMI_CEC_VERSION_1_4_B = 0x05;
332     /**
333      * Version constant for HDMI-CEC v2.0.
334      *
335      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION
336      */
337     public static final int HDMI_CEC_VERSION_2_0 = 0x06;
338     /**
339      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION
340      * @hide
341      */
342     @IntDef(prefix = { "HDMI_CEC_VERSION_" }, value = {
343             HDMI_CEC_VERSION_1_4_B,
344             HDMI_CEC_VERSION_2_0
345     })
346     @Retention(RetentionPolicy.SOURCE)
347     public @interface HdmiCecVersion {}
348 
349     // -- Whether the Routing Control feature is enabled or disabled.
350     /**
351      * Routing Control feature enabled.
352      *
353      * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL
354      */
355     public static final int ROUTING_CONTROL_ENABLED = 1;
356     /**
357      * Routing Control feature disabled.
358      *
359      * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL
360      */
361     public static final int ROUTING_CONTROL_DISABLED = 0;
362     /**
363      * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL
364      * @hide
365      */
366     @IntDef(prefix = { "ROUTING_CONTROL_" }, value = {
367             ROUTING_CONTROL_ENABLED,
368             ROUTING_CONTROL_DISABLED
369     })
370     @Retention(RetentionPolicy.SOURCE)
371     public @interface RoutingControl {}
372 
373     // -- Scope of CEC power control messages sent by a playback device.
374     /**
375      * Send CEC power control messages to TV only:
376      * Upon going to sleep, send {@code <Standby>} to TV only.
377      * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} but do not turn on the
378      * Audio system via {@code <System Audio Mode Request>}.
379      *
380      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
381      */
382     public static final String POWER_CONTROL_MODE_TV = "to_tv";
383     /**
384      * Send CEC power control messages to TV and Audio System:
385      * Upon going to sleep, send {@code <Standby>} to TV and Audio system.
386      * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} and attempt to turn on
387      * the Audio system via {@code <System Audio Mode Request>}.
388      *
389      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
390      */
391     public static final String POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM = "to_tv_and_audio_system";
392     /**
393      * Broadcast CEC power control messages to all devices in the network:
394      * Upon going to sleep, send {@code <Standby>} to all devices in the network.
395      * Upon waking up, attempt to turn on the TV via {@code <One Touch Play>} and attempt to turn on
396      * the Audio system via {@code <System Audio Mode Request>}.
397      *
398      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
399      */
400     public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
401     /**
402      * Don't send any CEC power control messages:
403      * Upon going to sleep, do not send any {@code <Standby>} message.
404      * Upon waking up, do not turn on the TV via {@code <One Touch Play>} and do not turn on the
405      * Audio system via {@code <System Audio Mode Request>}.
406      *
407      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
408      */
409     public static final String POWER_CONTROL_MODE_NONE = "none";
410     /**
411      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
412      * @hide
413      */
414     @StringDef(prefix = { "POWER_CONTROL_MODE_" }, value = {
415             POWER_CONTROL_MODE_TV,
416             POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM,
417             POWER_CONTROL_MODE_BROADCAST,
418             POWER_CONTROL_MODE_NONE
419     })
420     @Retention(RetentionPolicy.SOURCE)
421     public @interface PowerControlMode {}
422 
423     // -- Which power state action should be taken when Active Source is lost.
424     /**
425      * No action to be taken.
426      *
427      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
428      */
429     public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE = "none";
430     /**
431      * Go to standby immediately.
432      *
433      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
434      */
435     public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW = "standby_now";
436     /**
437      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
438      * @hide
439      */
440     @StringDef(prefix = { "POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_" }, value = {
441             POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE,
442             POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW
443     })
444     @Retention(RetentionPolicy.SOURCE)
445     public @interface ActiveSourceLostBehavior {}
446 
447     // -- Whether System Audio Control is enabled or disabled.
448     /**
449      * System Audio Control enabled.
450      *
451      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL
452      */
453     public static final int SYSTEM_AUDIO_CONTROL_ENABLED = 1;
454     /**
455      * System Audio Control disabled.
456      *
457      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL
458      */
459     public static final int SYSTEM_AUDIO_CONTROL_DISABLED = 0;
460     /**
461      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL
462      * @hide
463      */
464     @IntDef(prefix = { "SYSTEM_AUDIO_CONTROL_" }, value = {
465             SYSTEM_AUDIO_CONTROL_ENABLED,
466             SYSTEM_AUDIO_CONTROL_DISABLED
467     })
468     @Retention(RetentionPolicy.SOURCE)
469     public @interface SystemAudioControl {}
470 
471     // -- Whether System Audio Mode muting is enabled or disabled.
472     /**
473      * System Audio Mode muting enabled.
474      *
475      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING
476      */
477     public static final int SYSTEM_AUDIO_MODE_MUTING_ENABLED = 1;
478     /**
479      * System Audio Mode muting disabled.
480      *
481      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING
482      */
483     public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0;
484     /**
485      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING
486      * @hide
487      */
488     @IntDef(prefix = { "SYSTEM_AUDIO_MODE_MUTING_" }, value = {
489             SYSTEM_AUDIO_MODE_MUTING_ENABLED,
490             SYSTEM_AUDIO_MODE_MUTING_DISABLED
491     })
492     @Retention(RetentionPolicy.SOURCE)
493     public @interface SystemAudioModeMuting {}
494 
495     // -- Whether the HDMI CEC volume control is enabled or disabled.
496     /**
497      * HDMI CEC enabled.
498      *
499      * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE
500      */
501     public static final int VOLUME_CONTROL_ENABLED = 1;
502     /**
503      * HDMI CEC disabled.
504      *
505      * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE
506      */
507     public static final int VOLUME_CONTROL_DISABLED = 0;
508     /**
509      * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE
510      * @hide
511      */
512     @IntDef(prefix = { "VOLUME_CONTROL_" }, value = {
513             VOLUME_CONTROL_ENABLED,
514             VOLUME_CONTROL_DISABLED
515     })
516     @Retention(RetentionPolicy.SOURCE)
517     public @interface VolumeControl {}
518 
519     // -- Whether TV Wake on One Touch Play is enabled or disabled.
520     /**
521      * TV Wake on One Touch Play enabled.
522      *
523      * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY
524      */
525     public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED = 1;
526     /**
527      * TV Wake on One Touch Play disabled.
528      *
529      * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY
530      */
531     public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED = 0;
532     /**
533      * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY
534      * @hide
535      */
536     @IntDef(prefix = { "TV_WAKE_ON_ONE_TOUCH_PLAY_" }, value = {
537             TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED,
538             TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED
539     })
540     @Retention(RetentionPolicy.SOURCE)
541     public @interface TvWakeOnOneTouchPlay {}
542 
543     // -- Whether TV should send &lt;Standby&gt; on sleep.
544     /**
545      * Sending &lt;Standby&gt; on sleep.
546      *
547      * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP
548      */
549     public static final int TV_SEND_STANDBY_ON_SLEEP_ENABLED = 1;
550     /**
551      * Not sending &lt;Standby&gt; on sleep.
552      *
553      * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP
554      */
555     public static final int TV_SEND_STANDBY_ON_SLEEP_DISABLED = 0;
556     /**
557      * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP
558      * @hide
559      */
560     @IntDef(prefix = { "TV_SEND_STANDBY_ON_SLEEP_" }, value = {
561             TV_SEND_STANDBY_ON_SLEEP_ENABLED,
562             TV_SEND_STANDBY_ON_SLEEP_DISABLED
563     })
564     @Retention(RetentionPolicy.SOURCE)
565     public @interface TvSendStandbyOnSleep {}
566 
567     // -- Whether a playback device should act on an incoming {@code <Set Menu Language>} message.
568     /**
569      * Confirmation dialog should be shown upon receiving the CEC message.
570      *
571      * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
572      * @hide
573      */
574     public static final int SET_MENU_LANGUAGE_ENABLED = 1;
575     /**
576      * The message should be ignored.
577      *
578      * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
579      * @hide
580      */
581     public static final int SET_MENU_LANGUAGE_DISABLED = 0;
582     /**
583      * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
584      * @hide
585      */
586     @IntDef(prefix = { "SET_MENU_LANGUAGE_" }, value = {
587             SET_MENU_LANGUAGE_ENABLED,
588             SET_MENU_LANGUAGE_DISABLED
589     })
590     @Retention(RetentionPolicy.SOURCE)
591     public @interface SetMenuLanguage {}
592 
593     // -- The RC profile of a TV panel.
594     /**
595      * RC profile none.
596      *
597      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
598      * @hide
599      */
600     public static final int RC_PROFILE_TV_NONE = 0x0;
601     /**
602      * RC profile 1.
603      *
604      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
605      * @hide
606      */
607     public static final int RC_PROFILE_TV_ONE = 0x2;
608     /**
609      * RC profile 2.
610      *
611      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
612      * @hide
613      */
614     public static final int RC_PROFILE_TV_TWO = 0x6;
615     /**
616      * RC profile 3.
617      *
618      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
619      * @hide
620      */
621     public static final int RC_PROFILE_TV_THREE = 0xA;
622     /**
623      * RC profile 4.
624      *
625      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
626      * @hide
627      */
628     public static final int RC_PROFILE_TV_FOUR = 0xE;
629     /**
630      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV
631      * @hide
632      */
633     @IntDef(prefix = { "RC_PROFILE_TV_" }, value = {
634             RC_PROFILE_TV_NONE,
635             RC_PROFILE_TV_ONE,
636             RC_PROFILE_TV_TWO,
637             RC_PROFILE_TV_THREE,
638             RC_PROFILE_TV_FOUR
639     })
640     @Retention(RetentionPolicy.SOURCE)
641     public @interface RcProfileTv {}
642 
643     // -- RC profile parameter defining if a source handles a specific menu.
644     /**
645      * Handles the menu.
646      *
647      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU
648      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU
649      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU
650      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU
651      * @see HdmiControlManager#
652      * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU
653      * @hide
654      */
655     public static final int RC_PROFILE_SOURCE_MENU_HANDLED = 1;
656     /**
657      * Doesn't handle the menu.
658      *
659      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU
660      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU
661      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU
662      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU
663      * @see HdmiControlManager#
664      * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU
665      * @hide
666      */
667     public static final int RC_PROFILE_SOURCE_MENU_NOT_HANDLED = 0;
668     /**
669      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU
670      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU
671      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU
672      * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU
673      * @see HdmiControlManager#
674      * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU
675      * @hide
676      */
677     @IntDef(prefix = { "RC_PROFILE_SOURCE_MENU_" }, value = {
678             RC_PROFILE_SOURCE_MENU_HANDLED,
679             RC_PROFILE_SOURCE_MENU_NOT_HANDLED
680     })
681     @Retention(RetentionPolicy.SOURCE)
682     public @interface RcProfileSourceHandlesMenu {}
683 
684     // -- Whether the Short Audio Descriptor (SAD) for a specific codec should be queried or not.
685     /**
686      * Query the SAD.
687      *
688      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM
689      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD
690      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1
691      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3
692      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2
693      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC
694      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS
695      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC
696      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO
697      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP
698      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD
699      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD
700      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST
701      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO
702      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX
703      */
704     public static final int QUERY_SAD_ENABLED = 1;
705     /**
706      * Don't query the SAD.
707      *
708      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM
709      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD
710      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1
711      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3
712      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2
713      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC
714      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS
715      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC
716      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO
717      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP
718      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD
719      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD
720      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST
721      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO
722      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX
723      */
724     public static final int QUERY_SAD_DISABLED = 0;
725     /**
726      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM
727      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD
728      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1
729      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3
730      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2
731      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC
732      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS
733      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC
734      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO
735      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP
736      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD
737      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD
738      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST
739      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO
740      * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX
741      * @hide
742      */
743     @IntDef(prefix = { "QUERY_SAD_" }, value = {
744             QUERY_SAD_ENABLED,
745             QUERY_SAD_DISABLED
746     })
747     @Retention(RetentionPolicy.SOURCE)
748     public @interface SadPresenceInQuery {}
749 
750     // -- Settings available in the CEC Configuration.
751     /**
752      * Name of a setting deciding whether the CEC is enabled.
753      *
754      * @see HdmiControlManager#setHdmiCecEnabled(int)
755      */
756     public static final String CEC_SETTING_NAME_HDMI_CEC_ENABLED = "hdmi_cec_enabled";
757     /**
758      * Name of a setting controlling the version of HDMI-CEC used.
759      *
760      * @see HdmiControlManager#setHdmiCecVersion(int)
761      */
762     public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version";
763     /**
764      * Name of a setting deciding whether the Routing Control feature is enabled.
765      *
766      * @see HdmiControlManager#setRoutingControl(int)
767      */
768     public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control";
769     /**
770      * Name of a setting deciding on the power control mode.
771      *
772      * @see HdmiControlManager#setPowerControlMode(String)
773      */
774     public static final String CEC_SETTING_NAME_POWER_CONTROL_MODE = "power_control_mode";
775     /**
776      * Name of a setting deciding on power state action when losing Active Source.
777      *
778      * @see HdmiControlManager#setPowerStateChangeOnActiveSourceLost(String)
779      */
780     public static final String CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST =
781             "power_state_change_on_active_source_lost";
782     /**
783      * Name of a setting deciding whether System Audio Control is enabled.
784      *
785      * @see HdmiControlManager#setSystemAudioControl(int)
786      */
787     public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL =
788             "system_audio_control";
789     /**
790      * Name of a setting deciding whether System Audio Muting is allowed.
791      *
792      * @see HdmiControlManager#setSystemAudioModeMuting(int)
793      */
794     public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING =
795             "system_audio_mode_muting";
796     /**
797      * Controls whether volume control commands via HDMI CEC are enabled.
798      *
799      * <p>Effects on different device types:
800      * <table>
801      *     <tr><th>HDMI CEC device type</th><th>0: disabled</th><th>1: enabled</th></tr>
802      *     <tr>
803      *         <td>TV (type: 0)</td>
804      *         <td>Per CEC specification.</td>
805      *         <td>TV changes system volume. TV no longer reacts to incoming volume changes
806      *         via {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio
807      *         Status>}.</td>
808      *     </tr>
809      *     <tr>
810      *         <td>Playback device (type: 4)</td>
811      *         <td>Device sends volume commands to TV/Audio system via {@code <User Control
812      *         Pressed>}</td>
813      *         <td>Device does not send volume commands via {@code <User Control Pressed>}.</td>
814      *     </tr>
815      *     <tr>
816      *         <td>Audio device (type: 5)</td>
817      *         <td>Full "System Audio Control" capabilities.</td>
818      *         <td>Audio device no longer reacts to incoming {@code <User Control Pressed>}
819      *         volume commands. Audio device no longer reports volume changes via {@code
820      *         <Report Audio Status>}.</td>
821      *     </tr>
822      * </table>
823      *
824      * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged.
825      *
826      * @see HdmiControlManager#setHdmiCecVolumeControlEnabled(int)
827      */
828     public static final String CEC_SETTING_NAME_VOLUME_CONTROL_MODE =
829             "volume_control_enabled";
830     /**
831      * Name of a setting deciding whether the TV will automatically turn on upon reception
832      * of the CEC command &lt;Text View On&gt; or &lt;Image View On&gt;.
833      *
834      * @see HdmiControlManager#setTvWakeOnOneTouchPlay(int)
835      */
836     public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY =
837             "tv_wake_on_one_touch_play";
838     /**
839      * Name of a setting deciding whether the TV will also turn off other CEC devices
840      * when it goes to standby mode.
841      *
842      * @see HdmiControlManager#setTvSendStandbyOnSleep(int)
843      */
844     public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP =
845             "tv_send_standby_on_sleep";
846     /**
847      * Name of a setting deciding whether {@code <Set Menu Language>} message should be
848      * handled by the framework or ignored.
849      *
850      * @hide
851      */
852     public static final String CEC_SETTING_NAME_SET_MENU_LANGUAGE = "set_menu_language";
853     /**
854      * Name of a setting representing the RC profile of a TV panel.
855      *
856      * @hide
857      */
858     public static final String CEC_SETTING_NAME_RC_PROFILE_TV =
859             "rc_profile_tv";
860     /**
861      * Name of a setting representing the RC profile parameter defining if a source handles the root
862      * menu.
863      *
864      * @hide
865      */
866     public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU =
867             "rc_profile_source_handles_root_menu";
868     /**
869      * Name of a setting representing the RC profile parameter defining if a source handles the
870      * setup menu.
871      *
872      * @hide
873      */
874     public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU =
875             "rc_profile_source_handles_setup_menu";
876     /**
877      * Name of a setting representing the RC profile parameter defining if a source handles the
878      * contents menu.
879      *
880      * @hide
881      */
882     public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU =
883             "rc_profile_source_handles_contents_menu";
884     /**
885      * Name of a setting representing the RC profile parameter defining if a source handles the top
886      * menu.
887      *
888      * @hide
889      */
890     public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU =
891             "rc_profile_source_handles_top_menu";
892     /**
893      * Name of a setting representing the RC profile parameter defining if a source handles the
894      * media context sensitive menu.
895      *
896      * @hide
897      */
898     public static final String
899             CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU =
900             "rc_profile_source_handles_media_context_sensitive_menu";
901     /**
902      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the LPCM codec
903      * (0x1) should be queried or not.
904      *
905      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
906      */
907     public static final String CEC_SETTING_NAME_QUERY_SAD_LPCM = "query_sad_lpcm";
908     /**
909      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DD codec
910      * (0x2) should be queried or not.
911      *
912      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
913      */
914     public static final String CEC_SETTING_NAME_QUERY_SAD_DD = "query_sad_dd";
915     /**
916      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MPEG1 codec
917      * (0x3) should be queried or not.
918      *
919      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
920      */
921     public static final String CEC_SETTING_NAME_QUERY_SAD_MPEG1 = "query_sad_mpeg1";
922     /**
923      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MP3 codec
924      * (0x4) should be queried or not.
925      *
926      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
927      */
928     public static final String CEC_SETTING_NAME_QUERY_SAD_MP3 = "query_sad_mp3";
929     /**
930      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MPEG2 codec
931      * (0x5) should be queried or not.
932      *
933      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
934      */
935     public static final String CEC_SETTING_NAME_QUERY_SAD_MPEG2 = "query_sad_mpeg2";
936     /**
937      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the AAC codec
938      * (0x6) should be queried or not.
939      *
940      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
941      */
942     public static final String CEC_SETTING_NAME_QUERY_SAD_AAC = "query_sad_aac";
943     /**
944      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DTS codec
945      * (0x7) should be queried or not.
946      *
947      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
948      */
949     public static final String CEC_SETTING_NAME_QUERY_SAD_DTS = "query_sad_dts";
950     /**
951      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the ATRAC codec
952      * (0x8) should be queried or not.
953      *
954      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
955      */
956     public static final String CEC_SETTING_NAME_QUERY_SAD_ATRAC = "query_sad_atrac";
957     /**
958      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the ONEBITAUDIO
959      * codec (0x9) should be queried or not.
960      *
961      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
962      */
963     public static final String CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO = "query_sad_onebitaudio";
964     /**
965      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DDP codec
966      * (0xA) should be queried or not.
967      *
968      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
969      */
970     public static final String CEC_SETTING_NAME_QUERY_SAD_DDP = "query_sad_ddp";
971     /**
972      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DTSHD codec
973      * (0xB) should be queried or not.
974      *
975      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
976      */
977     public static final String CEC_SETTING_NAME_QUERY_SAD_DTSHD = "query_sad_dtshd";
978     /**
979      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the TRUEHD codec
980      * (0xC) should be queried or not.
981      *
982      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
983      */
984     public static final String CEC_SETTING_NAME_QUERY_SAD_TRUEHD = "query_sad_truehd";
985     /**
986      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DST codec
987      * (0xD) should be queried or not.
988      *
989      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
990      */
991     public static final String CEC_SETTING_NAME_QUERY_SAD_DST = "query_sad_dst";
992     /**
993      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the WMAPRO codec
994      * (0xE) should be queried or not.
995      *
996      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
997      */
998     public static final String CEC_SETTING_NAME_QUERY_SAD_WMAPRO = "query_sad_wmapro";
999     /**
1000      * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MAX codec
1001      * (0xF) should be queried or not.
1002      *
1003      * @see HdmiControlManager#setSadPresenceInQuery(String, int)
1004      */
1005     public static final String CEC_SETTING_NAME_QUERY_SAD_MAX = "query_sad_max";
1006     /**
1007      * @hide
1008      */
1009     @StringDef(prefix = { "CEC_SETTING_NAME_" }, value = {
1010         CEC_SETTING_NAME_HDMI_CEC_ENABLED,
1011         CEC_SETTING_NAME_HDMI_CEC_VERSION,
1012         CEC_SETTING_NAME_POWER_CONTROL_MODE,
1013         CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
1014         CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
1015         CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
1016         CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
1017         CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
1018         CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
1019         CEC_SETTING_NAME_SET_MENU_LANGUAGE,
1020         CEC_SETTING_NAME_RC_PROFILE_TV,
1021         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
1022         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
1023         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
1024         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
1025         CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
1026         CEC_SETTING_NAME_QUERY_SAD_LPCM,
1027         CEC_SETTING_NAME_QUERY_SAD_DD,
1028         CEC_SETTING_NAME_QUERY_SAD_MPEG1,
1029         CEC_SETTING_NAME_QUERY_SAD_MP3,
1030         CEC_SETTING_NAME_QUERY_SAD_MPEG2,
1031         CEC_SETTING_NAME_QUERY_SAD_AAC,
1032         CEC_SETTING_NAME_QUERY_SAD_DTS,
1033         CEC_SETTING_NAME_QUERY_SAD_ATRAC,
1034         CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
1035         CEC_SETTING_NAME_QUERY_SAD_DDP,
1036         CEC_SETTING_NAME_QUERY_SAD_DTSHD,
1037         CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
1038         CEC_SETTING_NAME_QUERY_SAD_DST,
1039         CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
1040         CEC_SETTING_NAME_QUERY_SAD_MAX,
1041     })
1042     public @interface CecSettingName {}
1043 
1044     /**
1045      * @hide
1046      */
1047     @StringDef(prefix = { "CEC_SETTING_NAME_QUERY_SAD_" }, value = {
1048             CEC_SETTING_NAME_QUERY_SAD_LPCM,
1049             CEC_SETTING_NAME_QUERY_SAD_DD,
1050             CEC_SETTING_NAME_QUERY_SAD_MPEG1,
1051             CEC_SETTING_NAME_QUERY_SAD_MP3,
1052             CEC_SETTING_NAME_QUERY_SAD_MPEG2,
1053             CEC_SETTING_NAME_QUERY_SAD_AAC,
1054             CEC_SETTING_NAME_QUERY_SAD_DTS,
1055             CEC_SETTING_NAME_QUERY_SAD_ATRAC,
1056             CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
1057             CEC_SETTING_NAME_QUERY_SAD_DDP,
1058             CEC_SETTING_NAME_QUERY_SAD_DTSHD,
1059             CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
1060             CEC_SETTING_NAME_QUERY_SAD_DST,
1061             CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
1062             CEC_SETTING_NAME_QUERY_SAD_MAX,
1063     })
1064     public @interface CecSettingSad {}
1065 
1066     // True if we have a logical device of type playback hosted in the system.
1067     private final boolean mHasPlaybackDevice;
1068     // True if we have a logical device of type TV hosted in the system.
1069     private final boolean mHasTvDevice;
1070     // True if we have a logical device of type audio system hosted in the system.
1071     private final boolean mHasAudioSystemDevice;
1072     // True if we have a logical device of type audio system hosted in the system.
1073     private final boolean mHasSwitchDevice;
1074     // True if it's a switch device.
1075     private final boolean mIsSwitchDevice;
1076 
1077     /**
1078      * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService,
1079      * which is a system private class. The right way to create an instance of this class is
1080      * using the factory Context.getSystemService.
1081      */
HdmiControlManager(IHdmiControlService service)1082     public HdmiControlManager(IHdmiControlService service) {
1083         mService = service;
1084         int[] types = null;
1085         if (mService != null) {
1086             try {
1087                 types = mService.getSupportedTypes();
1088             } catch (RemoteException e) {
1089                 throw e.rethrowFromSystemServer();
1090             }
1091         }
1092         mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
1093         mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK);
1094         mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1095         mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
1096         mIsSwitchDevice = HdmiProperties.is_switch().orElse(false);
1097     }
1098 
hasDeviceType(int[] types, int type)1099     private static boolean hasDeviceType(int[] types, int type) {
1100         if (types == null) {
1101             return false;
1102         }
1103         for (int t : types) {
1104             if (t == type) {
1105                 return true;
1106             }
1107         }
1108         return false;
1109     }
1110 
1111     /**
1112      * Gets an object that represents an HDMI-CEC logical device of a specified type.
1113      *
1114      * @param type CEC device type
1115      * @return {@link HdmiClient} instance. {@code null} on failure.
1116      * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
1117      * See {@link HdmiDeviceInfo#DEVICE_TV}
1118      * See {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}
1119      */
1120     @Nullable
1121     @SuppressLint("RequiresPermission")
getClient(int type)1122     public HdmiClient getClient(int type) {
1123         if (mService == null) {
1124             return null;
1125         }
1126         switch (type) {
1127             case HdmiDeviceInfo.DEVICE_TV:
1128                 return mHasTvDevice ? new HdmiTvClient(mService) : null;
1129             case HdmiDeviceInfo.DEVICE_PLAYBACK:
1130                 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
1131             case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
1132                 return mHasAudioSystemDevice ? new HdmiAudioSystemClient(mService) : null;
1133             case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH:
1134                 return (mHasSwitchDevice || mIsSwitchDevice)
1135                     ? new HdmiSwitchClient(mService) : null;
1136             default:
1137                 return null;
1138         }
1139     }
1140 
1141     /**
1142      * Gets an object that represents an HDMI-CEC logical device of type playback on the system.
1143      *
1144      * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
1145      * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
1146      * system if the system is configured to host more than one type of HDMI-CEC logical devices.
1147      *
1148      * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
1149      */
1150     @Nullable
1151     @SuppressLint("RequiresPermission")
getPlaybackClient()1152     public HdmiPlaybackClient getPlaybackClient() {
1153         return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
1154     }
1155 
1156     /**
1157      * Gets an object that represents an HDMI-CEC logical device of type TV on the system.
1158      *
1159      * <p>Used to send HDMI control messages to other devices and manage them through
1160      * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
1161      * system if the system is configured to host more than one type of HDMI-CEC logical devices.
1162      *
1163      * @return {@link HdmiTvClient} instance. {@code null} on failure.
1164      */
1165     @Nullable
1166     @SuppressLint("RequiresPermission")
getTvClient()1167     public HdmiTvClient getTvClient() {
1168         return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
1169     }
1170 
1171     /**
1172      * Gets an object that represents an HDMI-CEC logical device of type audio system on the system.
1173      *
1174      * <p>Used to send HDMI control messages to other devices like TV through HDMI bus. It is also
1175      * possible to communicate with other logical devices hosted in the same system if the system is
1176      * configured to host more than one type of HDMI-CEC logical devices.
1177      *
1178      * @return {@link HdmiAudioSystemClient} instance. {@code null} on failure.
1179      *
1180      * @hide
1181      */
1182     @Nullable
1183     @SuppressLint("RequiresPermission")
getAudioSystemClient()1184     public HdmiAudioSystemClient getAudioSystemClient() {
1185         return (HdmiAudioSystemClient) getClient(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
1186     }
1187 
1188     /**
1189      * Gets an object that represents an HDMI-CEC logical device of type switch on the system.
1190      *
1191      * <p>Used to send HDMI control messages to other devices (e.g. TVs) through HDMI bus.
1192      * It is also possible to communicate with other logical devices hosted in the same
1193      * system if the system is configured to host more than one type of HDMI-CEC logical device.
1194      *
1195      * @return {@link HdmiSwitchClient} instance. {@code null} on failure.
1196      */
1197     @Nullable
1198     @SuppressLint("RequiresPermission")
getSwitchClient()1199     public HdmiSwitchClient getSwitchClient() {
1200         return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
1201     }
1202 
1203     /**
1204      * Get a snapshot of the real-time status of the devices on the CEC bus.
1205      *
1206      * <p>This only applies to devices with switch functionality, which are devices with one
1207      * or more than one HDMI inputs.
1208      *
1209      * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices on the CEC bus. An
1210      * empty list will be returned if there is none.
1211      */
1212     @NonNull
getConnectedDevices()1213     public List<HdmiDeviceInfo> getConnectedDevices() {
1214         try {
1215             return mService.getDeviceList();
1216         } catch (RemoteException e) {
1217             throw e.rethrowFromSystemServer();
1218         }
1219     }
1220 
1221     /**
1222      * @removed
1223      * @deprecated Please use {@link #getConnectedDevices()} instead.
1224      */
1225     @Deprecated
getConnectedDevicesList()1226     public List<HdmiDeviceInfo> getConnectedDevicesList() {
1227         try {
1228             return mService.getDeviceList();
1229         } catch (RemoteException e) {
1230             throw e.rethrowFromSystemServer();
1231         }
1232     }
1233 
1234     /**
1235      * Power off the target device by sending CEC commands. Note that this device can't be the
1236      * current device itself.
1237      *
1238      * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
1239      *
1240      * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered off.
1241      */
powerOffDevice(@onNull HdmiDeviceInfo deviceInfo)1242     public void powerOffDevice(@NonNull HdmiDeviceInfo deviceInfo) {
1243         Objects.requireNonNull(deviceInfo);
1244         try {
1245             mService.powerOffRemoteDevice(
1246                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
1247         } catch (RemoteException e) {
1248             throw e.rethrowFromSystemServer();
1249         }
1250     }
1251 
1252     /**
1253      * @removed
1254      * @deprecated Please use {@link #powerOffDevice(deviceInfo)} instead.
1255      */
1256     @Deprecated
powerOffRemoteDevice(@onNull HdmiDeviceInfo deviceInfo)1257     public void powerOffRemoteDevice(@NonNull HdmiDeviceInfo deviceInfo) {
1258         Objects.requireNonNull(deviceInfo);
1259         try {
1260             mService.powerOffRemoteDevice(
1261                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
1262         } catch (RemoteException e) {
1263             throw e.rethrowFromSystemServer();
1264         }
1265     }
1266 
1267     /**
1268      * Power on the target device by sending CEC commands. Note that this device can't be the
1269      * current device itself.
1270      *
1271      * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
1272      *
1273      * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered on.
1274      *
1275      * @hide
1276      */
powerOnDevice(HdmiDeviceInfo deviceInfo)1277     public void powerOnDevice(HdmiDeviceInfo deviceInfo) {
1278         Objects.requireNonNull(deviceInfo);
1279         try {
1280             mService.powerOnRemoteDevice(
1281                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
1282         } catch (RemoteException e) {
1283             throw e.rethrowFromSystemServer();
1284         }
1285     }
1286 
1287     /**
1288      * @removed
1289      * @deprecated Please use {@link #powerOnDevice(deviceInfo)} instead.
1290      */
1291     @Deprecated
powerOnRemoteDevice(HdmiDeviceInfo deviceInfo)1292     public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
1293         Objects.requireNonNull(deviceInfo);
1294         try {
1295             mService.powerOnRemoteDevice(
1296                     deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
1297         } catch (RemoteException e) {
1298             throw e.rethrowFromSystemServer();
1299         }
1300     }
1301 
1302     /**
1303      * Request the target device to be the new Active Source by sending CEC commands. Note that
1304      * this device can't be the current device itself.
1305      *
1306      * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
1307      *
1308      * <p>If the target device responds to the command, the users should see the target device
1309      * streaming on their TVs.
1310      *
1311      * @param deviceInfo HdmiDeviceInfo of the target device
1312      */
setActiveSource(@onNull HdmiDeviceInfo deviceInfo)1313     public void setActiveSource(@NonNull HdmiDeviceInfo deviceInfo) {
1314         Objects.requireNonNull(deviceInfo);
1315         try {
1316             mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
1317         } catch (RemoteException e) {
1318             throw e.rethrowFromSystemServer();
1319         }
1320     }
1321 
1322     /**
1323      * @removed
1324      * @deprecated Please use {@link #setActiveSource(deviceInfo)} instead.
1325      */
1326     @Deprecated
requestRemoteDeviceToBecomeActiveSource(@onNull HdmiDeviceInfo deviceInfo)1327     public void requestRemoteDeviceToBecomeActiveSource(@NonNull HdmiDeviceInfo deviceInfo) {
1328         Objects.requireNonNull(deviceInfo);
1329         try {
1330             mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
1331         } catch (RemoteException e) {
1332             throw e.rethrowFromSystemServer();
1333         }
1334     }
1335 
1336     /**
1337      * Controls standby mode of the system. It will also try to turn on/off the connected devices if
1338      * necessary.
1339      *
1340      * @param isStandbyModeOn target status of the system's standby mode
1341      */
1342     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
setStandbyMode(boolean isStandbyModeOn)1343     public void setStandbyMode(boolean isStandbyModeOn) {
1344         try {
1345             mService.setStandbyMode(isStandbyModeOn);
1346         } catch (RemoteException e) {
1347             throw e.rethrowFromSystemServer();
1348         }
1349     }
1350 
1351     /**
1352      * For CEC source devices (OTT/STB/Audio system): toggle the power status of the HDMI-connected
1353      * display and follow the display's new power status.
1354      * For all other devices: no functionality.
1355      *
1356      * @hide
1357      */
1358     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
toggleAndFollowTvPower()1359     public void toggleAndFollowTvPower() {
1360         try {
1361             mService.toggleAndFollowTvPower();
1362         } catch (RemoteException e) {
1363             throw e.rethrowFromSystemServer();
1364         }
1365     }
1366 
1367     /**
1368      * Determines whether the HDMI CEC stack should handle KEYCODE_TV_POWER.
1369      *
1370      * @hide
1371      */
1372     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
shouldHandleTvPowerKey()1373     public boolean shouldHandleTvPowerKey() {
1374         try {
1375             return mService.shouldHandleTvPowerKey();
1376         } catch (RemoteException e) {
1377             throw e.rethrowFromSystemServer();
1378         }
1379     }
1380 
1381     /**
1382      * Controls whether volume control commands via HDMI CEC are enabled.
1383      *
1384      * <p>When disabled:
1385      * <ul>
1386      *     <li>the device will not send any HDMI CEC audio messages
1387      *     <li>received HDMI CEC audio messages are responded to with {@code <Feature Abort>}
1388      * </ul>
1389      *
1390      * <p>Effects on different device types:
1391      * <table>
1392      *     <tr><th>HDMI CEC device type</th><th>enabled</th><th>disabled</th></tr>
1393      *     <tr>
1394      *         <td>TV (type: 0)</td>
1395      *         <td>Per CEC specification.</td>
1396      *         <td>TV changes system volume. TV no longer reacts to incoming volume changes via
1397      *         {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio Status>}
1398      *         .</td>
1399      *     </tr>
1400      *     <tr>
1401      *         <td>Playback device (type: 4)</td>
1402      *         <td>Device sends volume commands to TV/Audio system via {@code <User Control
1403      *         Pressed>}</td><td>Device does not send volume commands via {@code <User Control
1404      *         Pressed>}.</td>
1405      *     </tr>
1406      *     <tr>
1407      *         <td>Audio device (type: 5)</td>
1408      *         <td>Full "System Audio Control" capabilities.</td>
1409      *         <td>Audio device no longer reacts to incoming {@code <User Control Pressed>}
1410      *         volume commands. Audio device no longer reports volume changes via {@code <Report
1411      *         Audio Status>}.</td>
1412      *     </tr>
1413      * </table>
1414      *
1415      * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged.
1416      *
1417      * @param hdmiCecVolumeControlEnabled target state of HDMI CEC volume control.
1418      * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE
1419      */
1420     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
setHdmiCecVolumeControlEnabled( @olumeControl int hdmiCecVolumeControlEnabled)1421     public void setHdmiCecVolumeControlEnabled(
1422             @VolumeControl int hdmiCecVolumeControlEnabled) {
1423         try {
1424             mService.setCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
1425                     hdmiCecVolumeControlEnabled);
1426         } catch (RemoteException e) {
1427             throw e.rethrowFromSystemServer();
1428         }
1429     }
1430 
1431     /**
1432      * Returns whether volume changes via HDMI CEC are enabled.
1433      *
1434      * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE
1435      */
1436     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1437     @VolumeControl
getHdmiCecVolumeControlEnabled()1438     public int getHdmiCecVolumeControlEnabled() {
1439         try {
1440             return mService.getCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE);
1441         } catch (RemoteException e) {
1442             throw e.rethrowFromSystemServer();
1443         }
1444     }
1445 
1446     /**
1447      * Gets whether the system is in system audio mode.
1448      *
1449      * @hide
1450      */
getSystemAudioMode()1451     public boolean getSystemAudioMode() {
1452         try {
1453             return mService.getSystemAudioMode();
1454         } catch (RemoteException e) {
1455             throw e.rethrowFromSystemServer();
1456         }
1457     }
1458 
1459     /**
1460      * Get the physical address of the device.
1461      *
1462      * <p>Physical address needs to be automatically adjusted when devices are phyiscally or
1463      * electrically added or removed from the device tree. Please see HDMI Specification Version
1464      * 1.4b 8.7 Physical Address for more details on the address discovery proccess.
1465      */
getPhysicalAddress()1466     public int getPhysicalAddress() {
1467         try {
1468             return mService.getPhysicalAddress();
1469         } catch (RemoteException e) {
1470             return INVALID_PHYSICAL_ADDRESS;
1471         }
1472     }
1473 
1474     /**
1475      * Check if the target device is connected to the current device.
1476      *
1477      * <p>The API also returns true if the current device is the target.
1478      *
1479      * @param targetDevice {@link HdmiDeviceInfo} of the target device.
1480      * @return true if {@code targetDevice} is directly or indirectly
1481      * connected to the current device.
1482      */
isDeviceConnected(@onNull HdmiDeviceInfo targetDevice)1483     public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
1484         Objects.requireNonNull(targetDevice);
1485         int physicalAddress = getPhysicalAddress();
1486         if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
1487             return false;
1488         }
1489         int targetPhysicalAddress = targetDevice.getPhysicalAddress();
1490         if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
1491             return false;
1492         }
1493         return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
1494             != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
1495     }
1496 
1497     /**
1498      * @removed
1499      * @deprecated Please use {@link #isDeviceConnected(targetDevice)} instead.
1500      */
1501     @Deprecated
isRemoteDeviceConnected(@onNull HdmiDeviceInfo targetDevice)1502     public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
1503         Objects.requireNonNull(targetDevice);
1504         int physicalAddress = getPhysicalAddress();
1505         if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
1506             return false;
1507         }
1508         int targetPhysicalAddress = targetDevice.getPhysicalAddress();
1509         if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
1510             return false;
1511         }
1512         return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
1513             != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
1514     }
1515 
1516     /**
1517      * Listener used to get hotplug event from HDMI port.
1518      */
1519     public interface HotplugEventListener {
onReceived(HdmiHotplugEvent event)1520         void onReceived(HdmiHotplugEvent event);
1521     }
1522 
1523     private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener>
1524             mHotplugEventListeners = new ArrayMap<>();
1525 
1526     /**
1527      * Listener used to get HDMI Control (CEC) status (enabled/disabled) and the connected display
1528      * status.
1529      * @hide
1530      */
1531     public interface HdmiControlStatusChangeListener {
1532         /**
1533          * Called when HDMI Control (CEC) is enabled/disabled.
1534          *
1535          * @param isCecEnabled status of HDMI Control
1536          * {@link android.hardware.hdmi.HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED}:
1537          * {@code HDMI_CEC_CONTROL_ENABLED} if enabled.
1538          * @param isCecAvailable status of CEC support of the connected display (the TV).
1539          * {@code true} if supported.
1540          *
1541          * Note: Value of isCecAvailable is only valid when isCecEnabled is true.
1542          **/
onStatusChange(@dmiControlManager.HdmiCecControl int isCecEnabled, boolean isCecAvailable)1543         void onStatusChange(@HdmiControlManager.HdmiCecControl int isCecEnabled,
1544                 boolean isCecAvailable);
1545     }
1546 
1547     private final ArrayMap<HdmiControlStatusChangeListener, IHdmiControlStatusChangeListener>
1548             mHdmiControlStatusChangeListeners = new ArrayMap<>();
1549 
1550     /**
1551      * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
1552      * @hide
1553      */
1554     public interface HdmiCecVolumeControlFeatureListener {
1555         /**
1556          * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
1557          *
1558          * @param hdmiCecVolumeControl status of HDMI CEC volume control feature
1559          * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(int)} ()}
1560          **/
onHdmiCecVolumeControlFeature(@olumeControl int hdmiCecVolumeControl)1561         void onHdmiCecVolumeControlFeature(@VolumeControl int hdmiCecVolumeControl);
1562     }
1563 
1564     private final ArrayMap<HdmiCecVolumeControlFeatureListener,
1565             IHdmiCecVolumeControlFeatureListener>
1566             mHdmiCecVolumeControlFeatureListeners = new ArrayMap<>();
1567 
1568     /**
1569      * Listener used to get vendor-specific commands.
1570      */
1571     public interface VendorCommandListener {
1572         /**
1573          * Called when a vendor command is received.
1574          *
1575          * @param srcAddress source logical address
1576          * @param destAddress destination logical address
1577          * @param params vendor-specific parameters
1578          * @param hasVendorId {@code true} if the command is &lt;Vendor Command
1579          *        With ID&gt;. The first 3 bytes of params is vendor id.
1580          */
onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId)1581         void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
1582 
1583         /**
1584          * The callback is called:
1585          * <ul>
1586          *     <li> before HdmiControlService is disabled.
1587          *     <li> after HdmiControlService is enabled and the local address is assigned.
1588          * </ul>
1589          * The client shouldn't hold the thread too long since this is a blocking call.
1590          *
1591          * @param enabled {@code true} if HdmiControlService is enabled.
1592          * @param reason the reason code why the state of HdmiControlService is changed.
1593          * @see #CONTROL_STATE_CHANGED_REASON_START
1594          * @see #CONTROL_STATE_CHANGED_REASON_SETTING
1595          * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
1596          * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
1597          */
onControlStateChanged(boolean enabled, int reason)1598         void onControlStateChanged(boolean enabled, int reason);
1599     }
1600 
1601     /**
1602      * Adds a listener to get informed of {@link HdmiHotplugEvent}.
1603      *
1604      * <p>To stop getting the notification,
1605      * use {@link #removeHotplugEventListener(HotplugEventListener)}.
1606      *
1607      * Note that each invocation of the callback will be executed on an arbitrary
1608      * Binder thread. This means that all callback implementations must be
1609      * thread safe. To specify the execution thread, use
1610      * {@link addHotplugEventListener(Executor, HotplugEventListener)}.
1611      *
1612      * @param listener {@link HotplugEventListener} instance
1613      * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
1614      */
1615     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
addHotplugEventListener(HotplugEventListener listener)1616     public void addHotplugEventListener(HotplugEventListener listener) {
1617         addHotplugEventListener(ConcurrentUtils.DIRECT_EXECUTOR, listener);
1618     }
1619 
1620     /**
1621      * Adds a listener to get informed of {@link HdmiHotplugEvent}.
1622      *
1623      * <p>To stop getting the notification,
1624      * use {@link #removeHotplugEventListener(HotplugEventListener)}.
1625      *
1626      * @param listener {@link HotplugEventListener} instance
1627      * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
1628      */
1629     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
addHotplugEventListener(@onNull @allbackExecutor Executor executor, @NonNull HotplugEventListener listener)1630     public void addHotplugEventListener(@NonNull @CallbackExecutor Executor executor,
1631             @NonNull HotplugEventListener listener) {
1632         if (mService == null) {
1633             Log.e(TAG, "HdmiControlService is not available");
1634             return;
1635         }
1636         if (mHotplugEventListeners.containsKey(listener)) {
1637             Log.e(TAG, "listener is already registered");
1638             return;
1639         }
1640         IHdmiHotplugEventListener wrappedListener =
1641                 getHotplugEventListenerWrapper(executor, listener);
1642         mHotplugEventListeners.put(listener, wrappedListener);
1643         try {
1644             mService.addHotplugEventListener(wrappedListener);
1645         } catch (RemoteException e) {
1646             throw e.rethrowFromSystemServer();
1647         }
1648     }
1649 
1650     /**
1651      * Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
1652      *
1653      * @param listener {@link HotplugEventListener} instance to be removed
1654      */
1655     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
removeHotplugEventListener(HotplugEventListener listener)1656     public void removeHotplugEventListener(HotplugEventListener listener) {
1657         if (mService == null) {
1658             Log.e(TAG, "HdmiControlService is not available");
1659             return;
1660         }
1661         IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener);
1662         if (wrappedListener == null) {
1663             Log.e(TAG, "tried to remove not-registered listener");
1664             return;
1665         }
1666         try {
1667             mService.removeHotplugEventListener(wrappedListener);
1668         } catch (RemoteException e) {
1669             throw e.rethrowFromSystemServer();
1670         }
1671     }
1672 
getHotplugEventListenerWrapper( Executor executor, final HotplugEventListener listener)1673     private IHdmiHotplugEventListener getHotplugEventListenerWrapper(
1674             Executor executor, final HotplugEventListener listener) {
1675         return new IHdmiHotplugEventListener.Stub() {
1676             @Override
1677             public void onReceived(HdmiHotplugEvent event) {
1678                 final long token = Binder.clearCallingIdentity();
1679                 try {
1680                     executor.execute(() -> listener.onReceived(event));
1681                 } finally {
1682                     Binder.restoreCallingIdentity(token);
1683                 }
1684             }
1685         };
1686     }
1687 
1688     /**
1689      * Adds a listener to get informed of {@link HdmiControlStatusChange}.
1690      *
1691      * <p>To stop getting the notification,
1692      * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}.
1693      *
1694      * Note that each invocation of the callback will be executed on an arbitrary
1695      * Binder thread. This means that all callback implementations must be
1696      * thread safe. To specify the execution thread, use
1697      * {@link addHdmiControlStatusChangeListener(Executor, HdmiControlStatusChangeListener)}.
1698      *
1699      * @param listener {@link HdmiControlStatusChangeListener} instance
1700      * @see HdmiControlManager#removeHdmiControlStatusChangeListener(
1701      * HdmiControlStatusChangeListener)
1702      *
1703      * @hide
1704      */
1705     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1706     public void addHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) {
1707         addHdmiControlStatusChangeListener(ConcurrentUtils.DIRECT_EXECUTOR, listener);
1708     }
1709 
1710     /**
1711      * Adds a listener to get informed of {@link HdmiControlStatusChange}.
1712      *
1713      * <p>To stop getting the notification,
1714      * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}.
1715      *
1716      * @param listener {@link HdmiControlStatusChangeListener} instance
1717      * @see HdmiControlManager#removeHdmiControlStatusChangeListener(
1718      * HdmiControlStatusChangeListener)
1719      *
1720      * @hide
1721      */
1722     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1723     public void addHdmiControlStatusChangeListener(@NonNull @CallbackExecutor Executor executor,
1724             @NonNull HdmiControlStatusChangeListener listener) {
1725         if (mService == null) {
1726             Log.e(TAG, "HdmiControlService is not available");
1727             return;
1728         }
1729         if (mHdmiControlStatusChangeListeners.containsKey(listener)) {
1730             Log.e(TAG, "listener is already registered");
1731             return;
1732         }
1733         IHdmiControlStatusChangeListener wrappedListener =
1734                 getHdmiControlStatusChangeListenerWrapper(executor, listener);
1735         mHdmiControlStatusChangeListeners.put(listener, wrappedListener);
1736         try {
1737             mService.addHdmiControlStatusChangeListener(wrappedListener);
1738         } catch (RemoteException e) {
1739             throw e.rethrowFromSystemServer();
1740         }
1741     }
1742 
1743     /**
1744      * Removes a listener to stop getting informed of {@link HdmiControlStatusChange}.
1745      *
1746      * @param listener {@link HdmiControlStatusChangeListener} instance to be removed
1747      *
1748      * @hide
1749      */
1750     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1751     public void removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) {
1752         if (mService == null) {
1753             Log.e(TAG, "HdmiControlService is not available");
1754             return;
1755         }
1756         IHdmiControlStatusChangeListener wrappedListener =
1757                 mHdmiControlStatusChangeListeners.remove(listener);
1758         if (wrappedListener == null) {
1759             Log.e(TAG, "tried to remove not-registered listener");
1760             return;
1761         }
1762         try {
1763             mService.removeHdmiControlStatusChangeListener(wrappedListener);
1764         } catch (RemoteException e) {
1765             throw e.rethrowFromSystemServer();
1766         }
1767     }
1768 
1769     private IHdmiControlStatusChangeListener getHdmiControlStatusChangeListenerWrapper(
1770             Executor executor, final HdmiControlStatusChangeListener listener) {
1771         return new IHdmiControlStatusChangeListener.Stub() {
1772             @Override
1773             public void onStatusChange(@HdmiCecControl int isCecEnabled, boolean isCecAvailable) {
1774                 final long token = Binder.clearCallingIdentity();
1775                 try {
1776                     executor.execute(() -> listener.onStatusChange(isCecEnabled, isCecAvailable));
1777                 } finally {
1778                     Binder.restoreCallingIdentity(token);
1779                 }
1780             }
1781         };
1782     }
1783 
1784     /**
1785      * Adds a listener to get informed of changes to the state of the HDMI CEC volume control
1786      * feature.
1787      *
1788      * Upon adding a listener, the current state of the HDMI CEC volume control feature will be
1789      * sent immediately.
1790      *
1791      * <p>To stop getting the notification,
1792      * use {@link #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)}.
1793      *
1794      * @param listener {@link HdmiCecVolumeControlFeatureListener} instance
1795      * @hide
1796      * @see #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)
1797      */
1798     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1799     public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor,
1800             @NonNull HdmiCecVolumeControlFeatureListener listener) {
1801         if (mService == null) {
1802             Log.e(TAG, "HdmiControlService is not available");
1803             return;
1804         }
1805         if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) {
1806             Log.e(TAG, "listener is already registered");
1807             return;
1808         }
1809         IHdmiCecVolumeControlFeatureListener wrappedListener =
1810                 createHdmiCecVolumeControlFeatureListenerWrapper(executor, listener);
1811         mHdmiCecVolumeControlFeatureListeners.put(listener, wrappedListener);
1812         try {
1813             mService.addHdmiCecVolumeControlFeatureListener(wrappedListener);
1814         } catch (RemoteException e) {
1815             throw e.rethrowFromSystemServer();
1816         }
1817     }
1818 
1819     /**
1820      * Removes a listener to stop getting informed of changes to the state of the HDMI CEC volume
1821      * control feature.
1822      *
1823      * @param listener {@link HdmiCecVolumeControlFeatureListener} instance to be removed
1824      * @hide
1825      */
1826     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1827     public void removeHdmiCecVolumeControlFeatureListener(
1828             HdmiCecVolumeControlFeatureListener listener) {
1829         if (mService == null) {
1830             Log.e(TAG, "HdmiControlService is not available");
1831             return;
1832         }
1833         IHdmiCecVolumeControlFeatureListener wrappedListener =
1834                 mHdmiCecVolumeControlFeatureListeners.remove(listener);
1835         if (wrappedListener == null) {
1836             Log.e(TAG, "tried to remove not-registered listener");
1837             return;
1838         }
1839         try {
1840             mService.removeHdmiCecVolumeControlFeatureListener(wrappedListener);
1841         } catch (RemoteException e) {
1842             throw e.rethrowFromSystemServer();
1843         }
1844     }
1845 
1846     private IHdmiCecVolumeControlFeatureListener createHdmiCecVolumeControlFeatureListenerWrapper(
1847             Executor executor, final HdmiCecVolumeControlFeatureListener listener) {
1848         return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() {
1849             @Override
1850             public void onHdmiCecVolumeControlFeature(int enabled) {
1851                 final long token = Binder.clearCallingIdentity();
1852                 try {
1853                     executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
1854                 } finally {
1855                     Binder.restoreCallingIdentity(token);
1856                 }
1857             }
1858         };
1859     }
1860 
1861     /**
1862      * Listener used to get setting change notification.
1863      */
1864     public interface CecSettingChangeListener {
1865         /**
1866          * Called when value of a setting changes.
1867          *
1868          * @param setting name of a CEC setting that changed
1869          */
1870         void onChange(@NonNull @CecSettingName String setting);
1871     }
1872 
1873     private final ArrayMap<String,
1874             ArrayMap<CecSettingChangeListener, IHdmiCecSettingChangeListener>>
1875                     mCecSettingChangeListeners = new ArrayMap<>();
1876 
1877     private void addCecSettingChangeListener(
1878             @NonNull @CecSettingName String setting,
1879             @NonNull @CallbackExecutor Executor executor,
1880             @NonNull CecSettingChangeListener listener) {
1881         if (mService == null) {
1882             Log.e(TAG, "HdmiControlService is not available");
1883             return;
1884         }
1885         if (mCecSettingChangeListeners.containsKey(setting)
1886                 && mCecSettingChangeListeners.get(setting).containsKey(listener)) {
1887             Log.e(TAG, "listener is already registered");
1888             return;
1889         }
1890         IHdmiCecSettingChangeListener wrappedListener =
1891                 getCecSettingChangeListenerWrapper(executor, listener);
1892         if (!mCecSettingChangeListeners.containsKey(setting)) {
1893             mCecSettingChangeListeners.put(setting, new ArrayMap<>());
1894         }
1895         mCecSettingChangeListeners.get(setting).put(listener, wrappedListener);
1896         try {
1897             mService.addCecSettingChangeListener(setting, wrappedListener);
1898         } catch (RemoteException e) {
1899             throw e.rethrowFromSystemServer();
1900         }
1901     }
1902 
1903     private void removeCecSettingChangeListener(
1904             @NonNull @CecSettingName String setting,
1905             @NonNull CecSettingChangeListener listener) {
1906         if (mService == null) {
1907             Log.e(TAG, "HdmiControlService is not available");
1908             return;
1909         }
1910         IHdmiCecSettingChangeListener wrappedListener =
1911                 !mCecSettingChangeListeners.containsKey(setting) ? null :
1912                     mCecSettingChangeListeners.get(setting).remove(listener);
1913         if (wrappedListener == null) {
1914             Log.e(TAG, "tried to remove not-registered listener");
1915             return;
1916         }
1917         try {
1918             mService.removeCecSettingChangeListener(setting, wrappedListener);
1919         } catch (RemoteException e) {
1920             throw e.rethrowFromSystemServer();
1921         }
1922     }
1923 
1924     private IHdmiCecSettingChangeListener getCecSettingChangeListenerWrapper(
1925             Executor executor, final CecSettingChangeListener listener) {
1926         return new IHdmiCecSettingChangeListener.Stub() {
1927             @Override
1928             public void onChange(String setting) {
1929                 final long token = Binder.clearCallingIdentity();
1930                 try {
1931                     executor.execute(() -> listener.onChange(setting));
1932                 } finally {
1933                     Binder.restoreCallingIdentity(token);
1934                 }
1935             }
1936         };
1937     }
1938 
1939     /**
1940      * Get a set of user-modifiable settings.
1941      *
1942      * @return a set of user-modifiable settings.
1943      * @throws RuntimeException when the HdmiControlService is not available.
1944      */
1945     @NonNull
1946     @CecSettingName
1947     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1948     public List<String> getUserCecSettings() {
1949         if (mService == null) {
1950             Log.e(TAG, "HdmiControlService is not available");
1951             throw new RuntimeException("HdmiControlService is not available");
1952         }
1953         try {
1954             return mService.getUserCecSettings();
1955         } catch (RemoteException e) {
1956             throw e.rethrowFromSystemServer();
1957         }
1958     }
1959 
1960     /**
1961      * Get a set of allowed values for a setting (string value-type).
1962      *
1963      * @param name name of the setting
1964      * @return a set of allowed values for a settings. {@code null} on failure.
1965      * @throws IllegalArgumentException when setting {@code name} does not exist.
1966      * @throws IllegalArgumentException when setting {@code name} value type is invalid.
1967      * @throws RuntimeException when the HdmiControlService is not available.
1968      */
1969     @NonNull
1970     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1971     public List<String> getAllowedCecSettingStringValues(@NonNull @CecSettingName String name) {
1972         if (mService == null) {
1973             Log.e(TAG, "HdmiControlService is not available");
1974             throw new RuntimeException("HdmiControlService is not available");
1975         }
1976         try {
1977             return mService.getAllowedCecSettingStringValues(name);
1978         } catch (RemoteException e) {
1979             throw e.rethrowFromSystemServer();
1980         }
1981     }
1982 
1983     /**
1984      * Get a set of allowed values for a setting (int value-type).
1985      *
1986      * @param name name of the setting
1987      * @return a set of allowed values for a settings. {@code null} on failure.
1988      * @throws IllegalArgumentException when setting {@code name} does not exist.
1989      * @throws IllegalArgumentException when setting {@code name} value type is invalid.
1990      * @throws RuntimeException when the HdmiControlService is not available.
1991      */
1992     @NonNull
1993     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
1994     public List<Integer> getAllowedCecSettingIntValues(@NonNull @CecSettingName String name) {
1995         if (mService == null) {
1996             Log.e(TAG, "HdmiControlService is not available");
1997             throw new RuntimeException("HdmiControlService is not available");
1998         }
1999         try {
2000             int[] allowedValues = mService.getAllowedCecSettingIntValues(name);
2001             return Arrays.stream(allowedValues).boxed().collect(Collectors.toList());
2002         } catch (RemoteException e) {
2003             throw e.rethrowFromSystemServer();
2004         }
2005     }
2006 
2007     /**
2008      * Set the global status of HDMI CEC.
2009      *
2010      * <p>This allows to enable/disable HDMI CEC on the device.
2011      */
2012     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2013     public void setHdmiCecEnabled(@NonNull @HdmiCecControl int value) {
2014         if (mService == null) {
2015             Log.e(TAG, "HdmiControlService is not available");
2016             throw new RuntimeException("HdmiControlService is not available");
2017         }
2018         try {
2019             mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
2020         } catch (RemoteException e) {
2021             throw e.rethrowFromSystemServer();
2022         }
2023     }
2024 
2025     /**
2026      * Get the current global status of HDMI CEC.
2027      *
2028      * <p>Reflects whether HDMI CEC is currently enabled on the device.
2029      */
2030     @NonNull
2031     @HdmiCecControl
2032     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2033     public int getHdmiCecEnabled() {
2034         if (mService == null) {
2035             Log.e(TAG, "HdmiControlService is not available");
2036             throw new RuntimeException("HdmiControlService is not available");
2037         }
2038         try {
2039             return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED);
2040         } catch (RemoteException e) {
2041             throw e.rethrowFromSystemServer();
2042         }
2043     }
2044 
2045     /**
2046      * Add change listener for global status of HDMI CEC.
2047      *
2048      * <p>To stop getting the notification,
2049      * use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}.
2050      *
2051      * Note that each invocation of the callback will be executed on an arbitrary
2052      * Binder thread. This means that all callback implementations must be
2053      * thread safe. To specify the execution thread, use
2054      * {@link addHdmiCecEnabledChangeListener(Executor, CecSettingChangeListener)}.
2055      */
2056     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2057     public void addHdmiCecEnabledChangeListener(@NonNull CecSettingChangeListener listener) {
2058         addHdmiCecEnabledChangeListener(ConcurrentUtils.DIRECT_EXECUTOR, listener);
2059     }
2060 
2061     /**
2062      * Add change listener for global status of HDMI CEC.
2063      *
2064      * <p>To stop getting the notification,
2065      * use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}.
2066      */
2067     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2068     public void addHdmiCecEnabledChangeListener(
2069             @NonNull @CallbackExecutor Executor executor,
2070             @NonNull CecSettingChangeListener listener) {
2071         addCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, executor, listener);
2072     }
2073 
2074     /**
2075      * Remove change listener for global status of HDMI CEC.
2076      */
2077     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2078     public void removeHdmiCecEnabledChangeListener(
2079             @NonNull CecSettingChangeListener listener) {
2080         removeCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, listener);
2081     }
2082 
2083     /**
2084      * Set the version of the HDMI CEC specification currently used.
2085      *
2086      * <p>Allows to select either CEC 1.4b or 2.0 to be used by the device.
2087      *
2088      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION
2089      */
2090     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2091     public void setHdmiCecVersion(@NonNull @HdmiCecVersion int value) {
2092         if (mService == null) {
2093             Log.e(TAG, "HdmiControlService is not available");
2094             throw new RuntimeException("HdmiControlService is not available");
2095         }
2096         try {
2097             mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION, value);
2098         } catch (RemoteException e) {
2099             throw e.rethrowFromSystemServer();
2100         }
2101     }
2102 
2103     /**
2104      * Get the version of the HDMI CEC specification currently used.
2105      *
2106      * <p>Reflects which CEC version 1.4b or 2.0 is currently used by the device.
2107      *
2108      * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION
2109      */
2110     @NonNull
2111     @HdmiCecVersion
2112     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2113     public int getHdmiCecVersion() {
2114         if (mService == null) {
2115             Log.e(TAG, "HdmiControlService is not available");
2116             throw new RuntimeException("HdmiControlService is not available");
2117         }
2118         try {
2119             return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION);
2120         } catch (RemoteException e) {
2121             throw e.rethrowFromSystemServer();
2122         }
2123     }
2124 
2125     /**
2126      * Set the status of Routing Control feature.
2127      *
2128      * <p>This allows to enable/disable Routing Control on the device.
2129      * If enabled, the switch device will route to the correct input source on
2130      * receiving Routing Control related messages. If disabled, you can only
2131      * switch the input via controls on this device.
2132      *
2133      * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL
2134      */
2135     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2136     public void setRoutingControl(@NonNull @RoutingControl int value) {
2137         if (mService == null) {
2138             Log.e(TAG, "HdmiControlService is not available");
2139             throw new RuntimeException("HdmiControlService is not available");
2140         }
2141         try {
2142             mService.setCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL, value);
2143         } catch (RemoteException e) {
2144             throw e.rethrowFromSystemServer();
2145         }
2146     }
2147 
2148     /**
2149      * Get the current status of Routing Control feature.
2150      *
2151      * <p>Reflects whether Routing Control is currently enabled on the device.
2152      * If enabled, the switch device will route to the correct input source on
2153      * receiving Routing Control related messages. If disabled, you can only
2154      * switch the input via controls on this device.
2155      *
2156      * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL
2157      */
2158     @NonNull
2159     @RoutingControl
2160     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2161     public int getRoutingControl() {
2162         if (mService == null) {
2163             Log.e(TAG, "HdmiControlService is not available");
2164             throw new RuntimeException("HdmiControlService is not available");
2165         }
2166         try {
2167             return mService.getCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL);
2168         } catch (RemoteException e) {
2169             throw e.rethrowFromSystemServer();
2170         }
2171     }
2172 
2173     /**
2174      * Set the status of Power Control.
2175      *
2176      * <p>Specifies to which devices Power Control messages should be sent:
2177      * only to the TV, broadcast to all devices, no power control messages.
2178      *
2179      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
2180      */
2181     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2182     public void setPowerControlMode(@NonNull @PowerControlMode String value) {
2183         if (mService == null) {
2184             Log.e(TAG, "HdmiControlService is not available");
2185             throw new RuntimeException("HdmiControlService is not available");
2186         }
2187         try {
2188             mService.setCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE, value);
2189         } catch (RemoteException e) {
2190             throw e.rethrowFromSystemServer();
2191         }
2192     }
2193 
2194     /**
2195      * Get the status of Power Control.
2196      *
2197      * <p>Reflects to which devices Power Control messages should be sent:
2198      * only to the TV, broadcast to all devices, no power control messages.
2199      *
2200      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE
2201      */
2202     @NonNull
2203     @PowerControlMode
2204     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2205     public String getPowerControlMode() {
2206         if (mService == null) {
2207             Log.e(TAG, "HdmiControlService is not available");
2208             throw new RuntimeException("HdmiControlService is not available");
2209         }
2210         try {
2211             return mService.getCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE);
2212         } catch (RemoteException e) {
2213             throw e.rethrowFromSystemServer();
2214         }
2215     }
2216 
2217     /**
2218      * Set the current power state behaviour when Active Source is lost.
2219      *
2220      * <p>Sets the action taken: do nothing or go to sleep immediately.
2221      *
2222      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
2223      */
2224     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2225     public void setPowerStateChangeOnActiveSourceLost(
2226             @NonNull @ActiveSourceLostBehavior String value) {
2227         if (mService == null) {
2228             Log.e(TAG, "HdmiControlService is not available");
2229             throw new RuntimeException("HdmiControlService is not available");
2230         }
2231         try {
2232             mService.setCecSettingStringValue(
2233                     CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, value);
2234         } catch (RemoteException e) {
2235             throw e.rethrowFromSystemServer();
2236         }
2237     }
2238 
2239     /**
2240      * Get the current power state behaviour when Active Source is lost.
2241      *
2242      * <p>Reflects the action taken: do nothing or go to sleep immediately.
2243      *
2244      * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST
2245      */
2246     @NonNull
2247     @ActiveSourceLostBehavior
2248     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2249     public String getPowerStateChangeOnActiveSourceLost() {
2250         if (mService == null) {
2251             Log.e(TAG, "HdmiControlService is not available");
2252             throw new RuntimeException("HdmiControlService is not available");
2253         }
2254         try {
2255             return mService.getCecSettingStringValue(
2256                     CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST);
2257         } catch (RemoteException e) {
2258             throw e.rethrowFromSystemServer();
2259         }
2260     }
2261 
2262     /**
2263      * Set the current status of System Audio Control.
2264      *
2265      * <p>Sets whether HDMI System Audio Control feature is enabled. If enabled,
2266      * TV or Audio System will try to turn on the System Audio Mode if there's a
2267      * connected CEC-enabled AV Receiver. Then an audio stream will be played on
2268      * the AVR instead of TV speaker or Audio System speakers. If disabled, the
2269      * System Audio Mode will never be activated.
2270      *
2271      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL
2272      */
2273     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2274     public void setSystemAudioControl(@NonNull @SystemAudioControl int value) {
2275         if (mService == null) {
2276             Log.e(TAG, "HdmiControlService is not available");
2277             throw new RuntimeException("HdmiControlService is not available");
2278         }
2279         try {
2280             mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL, value);
2281         } catch (RemoteException e) {
2282             throw e.rethrowFromSystemServer();
2283         }
2284     }
2285 
2286     /**
2287      * Get the current status of System Audio Control.
2288      *
2289      * <p>Reflects whether HDMI System Audio Control feature is enabled. If enabled,
2290      * TV or Audio System will try to turn on the System Audio Mode if there's a
2291      * connected CEC-enabled AV Receiver. Then an audio stream will be played on
2292      * the AVR instead of TV speaker or Audio System speakers. If disabled, the
2293      * System Audio Mode will never be activated.
2294      *
2295      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL
2296      */
2297     @NonNull
2298     @SystemAudioControl
2299     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2300     public int getSystemAudioControl() {
2301         if (mService == null) {
2302             Log.e(TAG, "HdmiControlService is not available");
2303             throw new RuntimeException("HdmiControlService is not available");
2304         }
2305         try {
2306             return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL);
2307         } catch (RemoteException e) {
2308             throw e.rethrowFromSystemServer();
2309         }
2310     }
2311 
2312     /**
2313      * Set the current status of System Audio Mode muting.
2314      *
2315      * <p>Sets whether the device should be muted when System Audio Mode is turned off.
2316      *
2317      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING
2318      */
2319     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2320     public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting int value) {
2321         if (mService == null) {
2322             Log.e(TAG, "HdmiControlService is not available");
2323             throw new RuntimeException("HdmiControlService is not available");
2324         }
2325         try {
2326             mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value);
2327         } catch (RemoteException e) {
2328             throw e.rethrowFromSystemServer();
2329         }
2330     }
2331 
2332     /**
2333      * Get the current status of System Audio Mode muting.
2334      *
2335      * <p>Reflects whether the device should be muted when System Audio Mode is turned off.
2336      *
2337      * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING
2338      */
2339     @NonNull
2340     @SystemAudioModeMuting
2341     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2342     public int getSystemAudioModeMuting() {
2343         if (mService == null) {
2344             Log.e(TAG, "HdmiControlService is not available");
2345             throw new RuntimeException("HdmiControlService is not available");
2346         }
2347         try {
2348             return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
2349         } catch (RemoteException e) {
2350             throw e.rethrowFromSystemServer();
2351         }
2352     }
2353 
2354     /**
2355      * Set the current status of TV Wake on One Touch Play.
2356      *
2357      * <p>Sets whether the TV should wake up upon reception of &lt;Text View On&gt;
2358      * or &lt;Image View On&gt;.
2359      *
2360      * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY
2361      */
2362     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2363     public void setTvWakeOnOneTouchPlay(@NonNull @TvWakeOnOneTouchPlay int value) {
2364         if (mService == null) {
2365             Log.e(TAG, "HdmiControlService is not available");
2366             throw new RuntimeException("HdmiControlService is not available");
2367         }
2368         try {
2369             mService.setCecSettingIntValue(CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, value);
2370         } catch (RemoteException e) {
2371             throw e.rethrowFromSystemServer();
2372         }
2373     }
2374 
2375     /**
2376      * Get the current status of TV Wake on One Touch Play.
2377      *
2378      * <p>Reflects whether the TV should wake up upon reception of &lt;Text View On&gt;
2379      * or &lt;Image View On&gt;.
2380      *
2381      * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY
2382      */
2383     @NonNull
2384     @TvWakeOnOneTouchPlay
2385     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2386     public int getTvWakeOnOneTouchPlay() {
2387         if (mService == null) {
2388             Log.e(TAG, "HdmiControlService is not available");
2389             throw new RuntimeException("HdmiControlService is not available");
2390         }
2391         try {
2392             return mService.getCecSettingIntValue(CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY);
2393         } catch (RemoteException e) {
2394             throw e.rethrowFromSystemServer();
2395         }
2396     }
2397 
2398     /**
2399      * Set the current status of TV send &lt;Standby&gt; on Sleep.
2400      *
2401      * <p>Sets whether the device will also turn off other CEC devices
2402      * when it goes to standby mode.
2403      *
2404      * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP
2405      */
2406     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2407     public void setTvSendStandbyOnSleep(@NonNull @TvSendStandbyOnSleep int value) {
2408         if (mService == null) {
2409             Log.e(TAG, "HdmiControlService is not available");
2410             throw new RuntimeException("HdmiControlService is not available");
2411         }
2412         try {
2413             mService.setCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, value);
2414         } catch (RemoteException e) {
2415             throw e.rethrowFromSystemServer();
2416         }
2417     }
2418 
2419     /**
2420      * Get the current status of TV send &lt;Standby&gt; on Sleep.
2421      *
2422      * <p>Reflects whether the device will also turn off other CEC devices
2423      * when it goes to standby mode.
2424      *
2425      * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP
2426      */
2427     @NonNull
2428     @TvSendStandbyOnSleep
2429     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2430     public int getTvSendStandbyOnSleep() {
2431         if (mService == null) {
2432             Log.e(TAG, "HdmiControlService is not available");
2433             throw new RuntimeException("HdmiControlService is not available");
2434         }
2435         try {
2436             return mService.getCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP);
2437         } catch (RemoteException e) {
2438             throw e.rethrowFromSystemServer();
2439         }
2440     }
2441 
2442     /**
2443      * Set presence of one Short Audio Descriptor (SAD) in the query.
2444      *
2445      * <p>Allows the caller to specify whether the SAD for a specific audio codec should be
2446      * present in the &lt;Request Short Audio Descriptor&gt; query. Each &lt;Request Short Audio
2447      * Descriptor&gt; message can carry at most 4 SADs at a time. This method allows the caller to
2448      * limit the amount of SADs queried and therefore limit the amount of CEC messages on the bus.
2449      *
2450      * <p>When an ARC connection is established, the TV sends a
2451      * &lt;Request Short Audio Descriptor&gt; query to the Audio System that it's connected to. If
2452      * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send
2453      * audio in that format to be output on the Audio System via ARC.
2454      * If a codec is not queried, the TV doesn't know if the connected Audio System supports this
2455      * SAD and doesn't send audio in that format to the Audio System.
2456      *
2457      * @param setting SAD to set.
2458      * @param value Presence to set the SAD to.
2459      */
2460     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2461     public void setSadPresenceInQuery(@NonNull @CecSettingSad String setting,
2462             @SadPresenceInQuery int value) {
2463         if (mService == null) {
2464             Log.e(TAG, "HdmiControlService is not available");
2465             throw new RuntimeException("HdmiControlService is not available");
2466         }
2467         try {
2468             mService.setCecSettingIntValue(setting, value);
2469         } catch (RemoteException e) {
2470             throw e.rethrowFromSystemServer();
2471         }
2472     }
2473 
2474     /**
2475      * Set presence of multiple Short Audio Descriptors (SADs) in the query.
2476      *
2477      * <p>Allows the caller to specify whether the SADs for specific audio codecs should be present
2478      * in the &lt;Request Short Audio Descriptor&gt; query. For audio codecs that are not specified,
2479      * the SAD's presence remains at its previous value. Each &lt;Request Short Audio Descriptor&gt;
2480      * message can carry at most 4 SADs at a time. This method allows the caller to limit the amount
2481      * of SADs queried and therefore limit the amount of CEC messages on the bus.
2482      *
2483      * <p>When an ARC connection is established, the TV sends a
2484      * &lt;Request Short Audio Descriptor&gt; query to the Audio System that it's connected to. If
2485      * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send
2486      * audio in that format to be output on the Audio System via ARC.
2487      * If a codec is not queried, the TV doesn't know if the connected Audio System supports this
2488      * SAD and doesn't send audio in that format to the Audio System.
2489      *
2490      *
2491      * @param settings SADs to set.
2492      * @param value Presence to set all specified SADs to.
2493      */
2494     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2495     public void setSadsPresenceInQuery(@NonNull @CecSettingSad List<String> settings,
2496             @SadPresenceInQuery int value) {
2497         if (mService == null) {
2498             Log.e(TAG, "HdmiControlService is not available");
2499             throw new RuntimeException("HdmiControlService is not available");
2500         }
2501         try {
2502             for (String sad : settings) {
2503                 mService.setCecSettingIntValue(sad, value);
2504             }
2505         } catch (RemoteException e) {
2506             throw e.rethrowFromSystemServer();
2507         }
2508     }
2509 
2510     /**
2511      * Get presence of one Short Audio Descriptor (SAD) in the query.
2512      *
2513      * <p>Reflects whether the SAD for a specific audio codec should be present in the
2514      * &lt;Request Short Audio Descriptor&gt; query.
2515      *
2516      * <p>When an ARC connection is established, the TV sends a
2517      * &lt;Request Short Audio Descriptor&gt; query to the Audio System that it's connected to. If
2518      * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send
2519      * audio in that format to be output on the Audio System via ARC.
2520      * If a codec is not queried, the TV doesn't know if the connected Audio System supports this
2521      * SAD and doesn't send audio in that format to the Audio System.
2522      *
2523      * @param setting SAD to get.
2524      * @return Current presence of the specified SAD.
2525      */
2526     @SadPresenceInQuery
2527     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
2528     public int getSadPresenceInQuery(@NonNull @CecSettingSad String setting) {
2529         if (mService == null) {
2530             Log.e(TAG, "HdmiControlService is not available");
2531             throw new RuntimeException("HdmiControlService is not available");
2532         }
2533         try {
2534             return mService.getCecSettingIntValue(setting);
2535         } catch (RemoteException e) {
2536             throw e.rethrowFromSystemServer();
2537         }
2538     }
2539 }
2540