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