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