/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.hdmi; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringDef; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.sysprop.HdmiProperties; import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ConcurrentUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.stream.Collectors; /** * The {@link HdmiControlManager} class is used to send HDMI control messages * to attached CEC devices. It also allows to control the eARC feature. * *

Provides various HDMI client instances that represent HDMI-CEC logical devices * hosted in the system. {@link #getTvClient()}, for instance will return an * {@link HdmiTvClient} object if the system is configured to host one. Android system * can host more than one logical CEC devices. If multiple types are configured they * all work as if they were independent logical devices running in the system. * * @hide */ @SystemApi @SystemService(Context.HDMI_CONTROL_SERVICE) @RequiresFeature(PackageManager.FEATURE_HDMI_CEC) public final class HdmiControlManager { private static final String TAG = "HdmiControlManager"; @Nullable private final IHdmiControlService mService; private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF; /** * A cache of the current device's physical address. When device's HDMI out port * is not connected to any device, it is set to {@link #INVALID_PHYSICAL_ADDRESS}. * *

Otherwise it is updated by the {@link ClientHotplugEventListener} registered * with {@link com.android.server.hdmi.HdmiControlService} by the * {@link #addHotplugEventListener(HotplugEventListener)} and the address is from * {@link com.android.server.hdmi.HdmiControlService#getPortInfo()} */ @GuardedBy("mLock") private int mLocalPhysicalAddress = INVALID_PHYSICAL_ADDRESS; private void setLocalPhysicalAddress(int physicalAddress) { synchronized (mLock) { mLocalPhysicalAddress = physicalAddress; } } private int getLocalPhysicalAddress() { synchronized (mLock) { return mLocalPhysicalAddress; } } private final Object mLock = new Object(); /** * Broadcast Action: Display OSD message. *

Send when the service has a message to display on screen for events * that need user's attention such as ARC status change. *

Always contains the extra fields {@link #EXTRA_MESSAGE_ID}. *

Requires {@link android.Manifest.permission#HDMI_CEC} to receive. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE"; // --- Messages for ACTION_OSD_MESSAGE --- /** * Message that ARC enabled device is connected to invalid port (non-ARC port). */ public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; /** * Message used by TV to receive volume status from Audio Receiver. It should check volume value * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRA_PARAM1}. If the * value is in range of [0,100], it is current volume of Audio Receiver. And there is another * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute. */ public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; /** * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of * the message to display on screen. */ public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID"; /** * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value * of the message. */ public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1"; /** * Used as an extra field in the Set Menu Language intent. Contains the requested locale. * @hide */ public static final String EXTRA_LOCALE = "android.hardware.hdmi.extra.LOCALE"; /** * Broadcast Action: Active Source status was recovered by the device. *

Send when device becomes the current active source such that the activity * HdmiCecActiveSourceLostActivity can be finished and cleared from the screen. *

Requires {@link android.Manifest.permission#HDMI_CEC} to receive. * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI = "android.hardware.hdmi.action.ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI"; /** * Volume value for mute state. */ public static final int AVR_VOLUME_MUTED = 101; public static final int POWER_STATUS_UNKNOWN = -1; public static final int POWER_STATUS_ON = 0; public static final int POWER_STATUS_STANDBY = 1; public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; /** @removed mistakenly exposed previously */ @IntDef ({ RESULT_SUCCESS, RESULT_TIMEOUT, RESULT_SOURCE_NOT_AVAILABLE, RESULT_TARGET_NOT_AVAILABLE, RESULT_ALREADY_IN_PROGRESS, RESULT_EXCEPTION, RESULT_INCORRECT_MODE, RESULT_COMMUNICATION_FAILED, }) @Retention(RetentionPolicy.SOURCE) public @interface ControlCallbackResult {} /** Control operation is successfully handled by the framework. */ public static final int RESULT_SUCCESS = 0; public static final int RESULT_TIMEOUT = 1; /** Source device that the application is using is not available. */ public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; /** Target device that the application is controlling is not available. */ public static final int RESULT_TARGET_NOT_AVAILABLE = 3; @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4; public static final int RESULT_EXCEPTION = 5; public static final int RESULT_INCORRECT_MODE = 6; public static final int RESULT_COMMUNICATION_FAILED = 7; public static final int DEVICE_EVENT_ADD_DEVICE = 1; public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // --- One Touch Recording success result /** Recording currently selected source. Indicates the status of a recording. */ public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01; /** Recording Digital Service. Indicates the status of a recording. */ public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 0x02; /** Recording Analogue Service. Indicates the status of a recording. */ public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 0x03; /** Recording External input. Indicates the status of a recording. */ public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 0x04; // --- One Touch Record failure result /** No recording – unable to record Digital Service. No suitable tuner. */ public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 0x05; /** No recording – unable to record Analogue Service. No suitable tuner. */ public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 0x06; /** * No recording – unable to select required service. as suitable tuner, but the requested * parameters are invalid or out of range for that tuner. */ public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 0x07; /** No recording – invalid External plug number */ public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 0x09; /** No recording – invalid External Physical Address */ public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x0A; /** No recording – CA system not supported */ public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 0x0B; /** No Recording – No or Insufficient CA Entitlements” */ public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x0C; /** No recording – Not allowed to copy source. Source is “copy never”. */ public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 0x0D; /** No recording – No further copies allowed */ public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 0x0E; /** No recording – No media */ public static final int ONE_TOUCH_RECORD_NO_MEDIA = 0x10; /** No recording – playing */ public static final int ONE_TOUCH_RECORD_PLAYING = 0x11; /** No recording – already recording */ public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 0x12; /** No recording – media protected */ public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 0x13; /** No recording – no source signal */ public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 0x14; /** No recording – media problem */ public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 0x15; /** No recording – not enough space available */ public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 0x16; /** No recording – Parental Lock On */ public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 0x17; /** Recording terminated normally */ public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 0x1A; /** Recording has already terminated */ public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 0x1B; /** No recording – other reason */ public static final int ONE_TOUCH_RECORD_OTHER_REASON = 0x1F; // From here extra message for recording that is not mentioned in CEC spec /** No recording. Previous recording request in progress. */ public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 0x30; /** No recording. Please check recorder and connection. */ public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 0x31; /** Cannot record currently displayed source. */ public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x32; /** CEC is disabled. */ public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 0x33; // --- Types for timer recording /** Timer recording type for digital service source. */ public static final int TIMER_RECORDING_TYPE_DIGITAL = 1; /** Timer recording type for analogue service source. */ public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2; /** Timer recording type for external source. */ public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3; // --- Timer Status Data /** [Timer Status Data/Media Info] - Media present and not protected. */ public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0x0; /** [Timer Status Data/Media Info] - Media present, but protected. */ public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 0x1; /** [Timer Status Data/Media Info] - Media not present. */ public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 0x2; /** [Timer Status Data/Programmed Info] - Enough space available for recording. */ public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 0x8; /** [Timer Status Data/Programmed Info] - Not enough space available for recording. */ public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 0x9; /** [Timer Status Data/Programmed Info] - Might not enough space available for recording. */ public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 0xB; /** [Timer Status Data/Programmed Info] - No media info available. */ public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 0xA; /** [Timer Status Data/Not Programmed Error Info] - No free timer available. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 0x1; /** [Timer Status Data/Not Programmed Error Info] - Date out of range. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 0x2; /** [Timer Status Data/Not Programmed Error Info] - Recording Sequence error. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 0x3; /** [Timer Status Data/Not Programmed Error Info] - Invalid External Plug Number. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 0x4; /** [Timer Status Data/Not Programmed Error Info] - Invalid External Physical Address. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 0x5; /** [Timer Status Data/Not Programmed Error Info] - CA system not supported. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 0x6; /** [Timer Status Data/Not Programmed Error Info] - No or insufficient CA Entitlements. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 0x7; /** [Timer Status Data/Not Programmed Error Info] - Does not support resolution. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 0x8; /** [Timer Status Data/Not Programmed Error Info] - Parental Lock On. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON= 0x9; /** [Timer Status Data/Not Programmed Error Info] - Clock Failure. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 0xA; /** [Timer Status Data/Not Programmed Error Info] - Duplicate: already programmed. */ public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 0xE; // --- Extra result value for timer recording. /** No extra error. */ public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0x00; /** No timer recording - check recorder and connection. */ public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 0x01; /** No timer recording - cannot record selected source. */ public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 0x02; /** CEC is disabled. */ public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 0x03; // -- Timer cleared status data code used for result of onClearTimerRecordingResult. /** Timer not cleared – recording. */ public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0x00; /** Timer not cleared – no matching. */ public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 0x01; /** Timer not cleared – no info available. */ public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 0x02; /** Timer cleared. */ public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 0x80; /** Clear timer error - check recorder and connection. */ public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 0xA0; /** Clear timer error - cannot clear timer for selected source. */ public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 0xA1; /** Clear timer error - CEC is disabled. */ public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2; /** The HdmiControlService is started. */ public static final int CONTROL_STATE_CHANGED_REASON_START = 0; /** The state of HdmiControlService is changed by changing of settings. */ public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1; /** The HdmiControlService is enabled to wake up. */ public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2; /** The HdmiControlService will be disabled to standby. */ public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3; // -- Whether the HDMI CEC is enabled or disabled. /** * HDMI CEC enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED */ public static final int HDMI_CEC_CONTROL_ENABLED = 1; /** * HDMI CEC disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED */ public static final int HDMI_CEC_CONTROL_DISABLED = 0; /** * @hide * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED */ @IntDef(prefix = { "HDMI_CEC_CONTROL_" }, value = { HDMI_CEC_CONTROL_ENABLED, HDMI_CEC_CONTROL_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface HdmiCecControl {} // -- Supported HDMI-CEC versions. /** * Version constant for HDMI-CEC v1.4b. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION */ public static final int HDMI_CEC_VERSION_1_4_B = 0x05; /** * Version constant for HDMI-CEC v2.0. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION */ public static final int HDMI_CEC_VERSION_2_0 = 0x06; /** * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION * @hide */ @IntDef(prefix = { "HDMI_CEC_VERSION_" }, value = { HDMI_CEC_VERSION_1_4_B, HDMI_CEC_VERSION_2_0 }) @Retention(RetentionPolicy.SOURCE) public @interface HdmiCecVersion {} // -- Whether the Routing Control feature is enabled or disabled. /** * Routing Control feature enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL */ public static final int ROUTING_CONTROL_ENABLED = 1; /** * Routing Control feature disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL */ public static final int ROUTING_CONTROL_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL * @hide */ @IntDef(prefix = { "ROUTING_CONTROL_" }, value = { ROUTING_CONTROL_ENABLED, ROUTING_CONTROL_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface RoutingControl {} // -- Whether the Soundbar mode feature is enabled or disabled. /** * Soundbar mode feature enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE */ public static final int SOUNDBAR_MODE_ENABLED = 1; /** * Soundbar mode feature disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE */ public static final int SOUNDBAR_MODE_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE * @hide */ @IntDef(prefix = { "SOUNDBAR_MODE" }, value = { SOUNDBAR_MODE_ENABLED, SOUNDBAR_MODE_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface SoundbarMode {} // -- Scope of CEC power control messages sent by a playback device. /** * Send CEC power control messages to TV only: * Upon going to sleep, send {@code } to TV only. * Upon waking up, attempt to turn on the TV via {@code } but do not turn on the * Audio system via {@code }. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ public static final String POWER_CONTROL_MODE_TV = "to_tv"; /** * Send CEC power control messages to TV and Audio System: * Upon going to sleep, send {@code } to TV and Audio system. * Upon waking up, attempt to turn on the TV via {@code } and attempt to turn on * the Audio system via {@code }. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ public static final String POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM = "to_tv_and_audio_system"; /** * Broadcast CEC power control messages to all devices in the network: * Upon going to sleep, send {@code } to all devices in the network. * Upon waking up, attempt to turn on the TV via {@code } and attempt to turn on * the Audio system via {@code }. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast"; /** * Don't send any CEC power control messages: * Upon going to sleep, do not send any {@code } message. * Upon waking up, do not turn on the TV via {@code } and do not turn on the * Audio system via {@code }. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ public static final String POWER_CONTROL_MODE_NONE = "none"; /** * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE * @hide */ @StringDef(prefix = { "POWER_CONTROL_MODE_" }, value = { POWER_CONTROL_MODE_TV, POWER_CONTROL_MODE_TV_AND_AUDIO_SYSTEM, POWER_CONTROL_MODE_BROADCAST, POWER_CONTROL_MODE_NONE }) @Retention(RetentionPolicy.SOURCE) public @interface PowerControlMode {} // -- Which power state action should be taken when Active Source is lost. /** * No action to be taken. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST */ public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE = "none"; /** * Go to standby immediately. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST */ public static final String POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW = "standby_now"; /** * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST * @hide */ @StringDef(prefix = { "POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_" }, value = { POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE, POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW }) @Retention(RetentionPolicy.SOURCE) public @interface ActiveSourceLostBehavior {} // -- Whether System Audio Control is enabled or disabled. /** * System Audio Control enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL */ public static final int SYSTEM_AUDIO_CONTROL_ENABLED = 1; /** * System Audio Control disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL */ public static final int SYSTEM_AUDIO_CONTROL_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL * @hide */ @IntDef(prefix = { "SYSTEM_AUDIO_CONTROL_" }, value = { SYSTEM_AUDIO_CONTROL_ENABLED, SYSTEM_AUDIO_CONTROL_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface SystemAudioControl {} // -- Whether System Audio Mode muting is enabled or disabled. /** * System Audio Mode muting enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING */ public static final int SYSTEM_AUDIO_MODE_MUTING_ENABLED = 1; /** * System Audio Mode muting disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING */ public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING * @hide */ @IntDef(prefix = { "SYSTEM_AUDIO_MODE_MUTING_" }, value = { SYSTEM_AUDIO_MODE_MUTING_ENABLED, SYSTEM_AUDIO_MODE_MUTING_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface SystemAudioModeMuting {} // -- Whether the HDMI CEC volume control is enabled or disabled. /** * HDMI CEC enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE */ public static final int VOLUME_CONTROL_ENABLED = 1; /** * HDMI CEC disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE */ public static final int VOLUME_CONTROL_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE * @hide */ @IntDef(prefix = { "VOLUME_CONTROL_" }, value = { VOLUME_CONTROL_ENABLED, VOLUME_CONTROL_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface VolumeControl {} // -- Whether TV Wake on One Touch Play is enabled or disabled. /** * TV Wake on One Touch Play enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY */ public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED = 1; /** * TV Wake on One Touch Play disabled. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY */ public static final int TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY * @hide */ @IntDef(prefix = { "TV_WAKE_ON_ONE_TOUCH_PLAY_" }, value = { TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED, TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface TvWakeOnOneTouchPlay {} // -- Whether TV should send <Standby> on sleep. /** * Sending <Standby> on sleep. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP */ public static final int TV_SEND_STANDBY_ON_SLEEP_ENABLED = 1; /** * Not sending <Standby> on sleep. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP */ public static final int TV_SEND_STANDBY_ON_SLEEP_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP * @hide */ @IntDef(prefix = { "TV_SEND_STANDBY_ON_SLEEP_" }, value = { TV_SEND_STANDBY_ON_SLEEP_ENABLED, TV_SEND_STANDBY_ON_SLEEP_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface TvSendStandbyOnSleep {} // -- Whether a playback device should act on an incoming {@code } message. /** * Confirmation dialog should be shown upon receiving the CEC message. * * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE * @hide */ public static final int SET_MENU_LANGUAGE_ENABLED = 1; /** * The message should be ignored. * * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE * @hide */ public static final int SET_MENU_LANGUAGE_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE * @hide */ @IntDef(prefix = { "SET_MENU_LANGUAGE_" }, value = { SET_MENU_LANGUAGE_ENABLED, SET_MENU_LANGUAGE_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface SetMenuLanguage {} // -- The RC profile of a TV panel. /** * RC profile none. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ public static final int RC_PROFILE_TV_NONE = 0x0; /** * RC profile 1. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ public static final int RC_PROFILE_TV_ONE = 0x2; /** * RC profile 2. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ public static final int RC_PROFILE_TV_TWO = 0x6; /** * RC profile 3. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ public static final int RC_PROFILE_TV_THREE = 0xA; /** * RC profile 4. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ public static final int RC_PROFILE_TV_FOUR = 0xE; /** * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_TV * @hide */ @IntDef(prefix = { "RC_PROFILE_TV_" }, value = { RC_PROFILE_TV_NONE, RC_PROFILE_TV_ONE, RC_PROFILE_TV_TWO, RC_PROFILE_TV_THREE, RC_PROFILE_TV_FOUR }) @Retention(RetentionPolicy.SOURCE) public @interface RcProfileTv {} // -- RC profile parameter defining if a source handles a specific menu. /** * Handles the menu. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU * @see HdmiControlManager# * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU * @hide */ public static final int RC_PROFILE_SOURCE_MENU_HANDLED = 1; /** * Doesn't handle the menu. * * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU * @see HdmiControlManager# * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU * @hide */ public static final int RC_PROFILE_SOURCE_MENU_NOT_HANDLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU * @see HdmiControlManager#CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU * @see HdmiControlManager# * CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU * @hide */ @IntDef(prefix = { "RC_PROFILE_SOURCE_MENU_" }, value = { RC_PROFILE_SOURCE_MENU_HANDLED, RC_PROFILE_SOURCE_MENU_NOT_HANDLED }) @Retention(RetentionPolicy.SOURCE) public @interface RcProfileSourceHandlesMenu {} // -- Whether the Short Audio Descriptor (SAD) for a specific codec should be queried or not. /** * Query the SAD. * * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX */ public static final int QUERY_SAD_ENABLED = 1; /** * Don't query the SAD. * * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX */ public static final int QUERY_SAD_DISABLED = 0; /** * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_LPCM * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG1 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MP3 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MPEG2 * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_AAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTS * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ATRAC * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DDP * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DTSHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_TRUEHD * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_DST * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_WMAPRO * @see HdmiControlManager#CEC_SETTING_NAME_QUERY_SAD_MAX * @hide */ @IntDef(prefix = { "QUERY_SAD_" }, value = { QUERY_SAD_ENABLED, QUERY_SAD_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface SadPresenceInQuery {} // -- Whether eARC is enabled or disabled. /** * eARC enabled. * * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED */ public static final int EARC_FEATURE_ENABLED = 1; /** * eARC disabled. * * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED */ public static final int EARC_FEATURE_DISABLED = 0; /** * @hide * * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED */ @IntDef(prefix = { "EARC_FEATURE" }, value = { EARC_FEATURE_ENABLED, EARC_FEATURE_DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface EarcFeature {} // -- Settings available in the CEC Configuration. /** * Name of a setting deciding whether the CEC is enabled. * * @see HdmiControlManager#setHdmiCecEnabled(int) */ public static final String CEC_SETTING_NAME_HDMI_CEC_ENABLED = "hdmi_cec_enabled"; /** * Name of a setting controlling the version of HDMI-CEC used. * * @see HdmiControlManager#setHdmiCecVersion(int) */ public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version"; /** * Name of a setting deciding whether the Routing Control feature is enabled. * * @see HdmiControlManager#setRoutingControl(int) */ public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control"; /** * Name of a setting deciding whether the Soundbar mode feature is enabled. * Before exposing this setting make sure the hardware supports it, otherwise, you may * experience multiple issues. * * @see HdmiControlManager#setSoundbarMode(int) */ public static final String CEC_SETTING_NAME_SOUNDBAR_MODE = "soundbar_mode"; /** * Name of a setting deciding on the power control mode. * * @see HdmiControlManager#setPowerControlMode(String) */ public static final String CEC_SETTING_NAME_POWER_CONTROL_MODE = "power_control_mode"; /** * Name of a setting deciding on power state action when losing Active Source. * * @see HdmiControlManager#setPowerStateChangeOnActiveSourceLost(String) */ public static final String CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST = "power_state_change_on_active_source_lost"; /** * Name of a setting deciding whether System Audio Control is enabled. * * @see HdmiControlManager#setSystemAudioControl(int) */ public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL = "system_audio_control"; /** * Name of a setting deciding whether System Audio Muting is allowed. * * @see HdmiControlManager#setSystemAudioModeMuting(int) */ public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING = "system_audio_mode_muting"; /** * Controls whether volume control commands via HDMI CEC are enabled. * *

Effects on different device types: * * * * * * * * * * * * * * * * * *
HDMI CEC device type0: disabled1: enabled
TV (type: 0)Per CEC specification.TV changes system volume. TV no longer reacts to incoming volume changes * via {@code }. TV no longer handles {@code }.
Playback device (type: 4)Device sends volume commands to TV/Audio system via {@code }Device does not send volume commands via {@code }.
Audio device (type: 5)Full "System Audio Control" capabilities.Audio device no longer reacts to incoming {@code } * volume commands. Audio device no longer reports volume changes via {@code * }.
* *

Due to the resulting behavior, usage on TV and Audio devices is discouraged. * * @see HdmiControlManager#setHdmiCecVolumeControlEnabled(int) */ public static final String CEC_SETTING_NAME_VOLUME_CONTROL_MODE = "volume_control_enabled"; /** * Name of a setting deciding whether the TV will automatically turn on upon reception * of the CEC command <Text View On> or <Image View On>. * * @see HdmiControlManager#setTvWakeOnOneTouchPlay(int) */ public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY = "tv_wake_on_one_touch_play"; /** * Name of a setting deciding whether the TV will also turn off other CEC devices * when it goes to standby mode. * * @see HdmiControlManager#setTvSendStandbyOnSleep(int) */ public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep"; /** * Name of a setting deciding whether {@code } message should be * handled by the framework or ignored. * * @hide */ public static final String CEC_SETTING_NAME_SET_MENU_LANGUAGE = "set_menu_language"; /** * Name of a setting representing the RC profile of a TV panel. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_TV = "rc_profile_tv"; /** * Name of a setting representing the RC profile parameter defining if a source handles the root * menu. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU = "rc_profile_source_handles_root_menu"; /** * Name of a setting representing the RC profile parameter defining if a source handles the * setup menu. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU = "rc_profile_source_handles_setup_menu"; /** * Name of a setting representing the RC profile parameter defining if a source handles the * contents menu. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU = "rc_profile_source_handles_contents_menu"; /** * Name of a setting representing the RC profile parameter defining if a source handles the top * menu. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU = "rc_profile_source_handles_top_menu"; /** * Name of a setting representing the RC profile parameter defining if a source handles the * media context sensitive menu. * * @hide */ public static final String CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU = "rc_profile_source_handles_media_context_sensitive_menu"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the LPCM codec * (0x1) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_LPCM = "query_sad_lpcm"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DD codec * (0x2) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_DD = "query_sad_dd"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MPEG1 codec * (0x3) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_MPEG1 = "query_sad_mpeg1"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MP3 codec * (0x4) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_MP3 = "query_sad_mp3"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MPEG2 codec * (0x5) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_MPEG2 = "query_sad_mpeg2"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the AAC codec * (0x6) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_AAC = "query_sad_aac"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DTS codec * (0x7) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_DTS = "query_sad_dts"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the ATRAC codec * (0x8) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_ATRAC = "query_sad_atrac"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the ONEBITAUDIO * codec (0x9) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO = "query_sad_onebitaudio"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DDP codec * (0xA) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_DDP = "query_sad_ddp"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DTSHD codec * (0xB) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_DTSHD = "query_sad_dtshd"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the TRUEHD codec * (0xC) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_TRUEHD = "query_sad_truehd"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the DST codec * (0xD) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_DST = "query_sad_dst"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the WMAPRO codec * (0xE) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_WMAPRO = "query_sad_wmapro"; /** * Name of a setting representing whether the Short Audio Descriptor (SAD) for the MAX codec * (0xF) should be queried or not. * * @see HdmiControlManager#setSadPresenceInQuery(String, int) */ public static final String CEC_SETTING_NAME_QUERY_SAD_MAX = "query_sad_max"; /** * Name of a setting representing whether eARC is enabled or not. * * @see HdmiControlManager#setEarcEnabled(int) */ public static final String SETTING_NAME_EARC_ENABLED = "earc_enabled"; /** * @hide */ // TODO(b/240379115): change names of CEC settings so that their prefix matches with the other // HDMI control settings. @StringDef(value = { CEC_SETTING_NAME_HDMI_CEC_ENABLED, CEC_SETTING_NAME_HDMI_CEC_VERSION, CEC_SETTING_NAME_ROUTING_CONTROL, CEC_SETTING_NAME_SOUNDBAR_MODE, CEC_SETTING_NAME_POWER_CONTROL_MODE, CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL, CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, CEC_SETTING_NAME_VOLUME_CONTROL_MODE, CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, CEC_SETTING_NAME_SET_MENU_LANGUAGE, CEC_SETTING_NAME_RC_PROFILE_TV, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU, CEC_SETTING_NAME_QUERY_SAD_LPCM, CEC_SETTING_NAME_QUERY_SAD_DD, CEC_SETTING_NAME_QUERY_SAD_MPEG1, CEC_SETTING_NAME_QUERY_SAD_MP3, CEC_SETTING_NAME_QUERY_SAD_MPEG2, CEC_SETTING_NAME_QUERY_SAD_AAC, CEC_SETTING_NAME_QUERY_SAD_DTS, CEC_SETTING_NAME_QUERY_SAD_ATRAC, CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO, CEC_SETTING_NAME_QUERY_SAD_DDP, CEC_SETTING_NAME_QUERY_SAD_DTSHD, CEC_SETTING_NAME_QUERY_SAD_TRUEHD, CEC_SETTING_NAME_QUERY_SAD_DST, CEC_SETTING_NAME_QUERY_SAD_WMAPRO, CEC_SETTING_NAME_QUERY_SAD_MAX, SETTING_NAME_EARC_ENABLED, }) @Retention(RetentionPolicy.SOURCE) public @interface SettingName {} /** * @hide */ @StringDef(prefix = { "CEC_SETTING_NAME_QUERY_SAD_" }, value = { CEC_SETTING_NAME_QUERY_SAD_LPCM, CEC_SETTING_NAME_QUERY_SAD_DD, CEC_SETTING_NAME_QUERY_SAD_MPEG1, CEC_SETTING_NAME_QUERY_SAD_MP3, CEC_SETTING_NAME_QUERY_SAD_MPEG2, CEC_SETTING_NAME_QUERY_SAD_AAC, CEC_SETTING_NAME_QUERY_SAD_DTS, CEC_SETTING_NAME_QUERY_SAD_ATRAC, CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO, CEC_SETTING_NAME_QUERY_SAD_DDP, CEC_SETTING_NAME_QUERY_SAD_DTSHD, CEC_SETTING_NAME_QUERY_SAD_TRUEHD, CEC_SETTING_NAME_QUERY_SAD_DST, CEC_SETTING_NAME_QUERY_SAD_WMAPRO, CEC_SETTING_NAME_QUERY_SAD_MAX, }) @Retention(RetentionPolicy.SOURCE) public @interface CecSettingSad {} // True if we have a logical device of type playback hosted in the system. private final boolean mHasPlaybackDevice; // True if we have a logical device of type TV hosted in the system. private final boolean mHasTvDevice; // True if we have a logical device of type audio system hosted in the system. private final boolean mHasAudioSystemDevice; // True if we have a logical device of type audio system hosted in the system. private final boolean mHasSwitchDevice; // True if it's a switch device. private final boolean mIsSwitchDevice; /** * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService, * which is a system private class. The right way to create an instance of this class is * using the factory Context.getSystemService. */ public HdmiControlManager(IHdmiControlService service) { mService = service; int[] types = null; if (mService != null) { try { types = mService.getSupportedTypes(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV); mHasPlaybackDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PLAYBACK); mHasAudioSystemDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH); mIsSwitchDevice = HdmiProperties.is_switch().orElse(false); addHotplugEventListener(new ClientHotplugEventListener()); } private final class ClientHotplugEventListener implements HotplugEventListener { @Override public void onReceived(HdmiHotplugEvent event) { List ports = new ArrayList<>(); try { ports = mService.getPortInfo(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } if (ports.isEmpty()) { Log.e(TAG, "Can't find port info, not updating connected status. " + "Hotplug event:" + event); return; } // If the HDMI OUT port is plugged or unplugged, update the mLocalPhysicalAddress for (HdmiPortInfo port : ports) { if (port.getId() == event.getPort()) { if (port.getType() == HdmiPortInfo.PORT_OUTPUT) { setLocalPhysicalAddress( event.isConnected() ? port.getAddress() : INVALID_PHYSICAL_ADDRESS); } break; } } } } private static boolean hasDeviceType(int[] types, int type) { if (types == null) { return false; } for (int t : types) { if (t == type) { return true; } } return false; } /** * Gets an object that represents an HDMI-CEC logical device of a specified type. * * @param type CEC device type * @return {@link HdmiClient} instance. {@code null} on failure. * See {@link HdmiDeviceInfo#DEVICE_PLAYBACK} * See {@link HdmiDeviceInfo#DEVICE_TV} * See {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} */ @Nullable @SuppressLint("RequiresPermission") public HdmiClient getClient(int type) { if (mService == null) { return null; } switch (type) { case HdmiDeviceInfo.DEVICE_TV: return mHasTvDevice ? new HdmiTvClient(mService) : null; case HdmiDeviceInfo.DEVICE_PLAYBACK: return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null; case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM: try { if ((mService.getCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE) == SOUNDBAR_MODE_ENABLED && mHasPlaybackDevice) || mHasAudioSystemDevice) { return new HdmiAudioSystemClient(mService); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return null; case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH: return (mHasSwitchDevice || mIsSwitchDevice) ? new HdmiSwitchClient(mService) : null; default: return null; } } /** * Gets an object that represents an HDMI-CEC logical device of type playback on the system. * *

Used to send HDMI control messages to other devices like TV or audio amplifier through * HDMI bus. It is also possible to communicate with other logical devices hosted in the same * system if the system is configured to host more than one type of HDMI-CEC logical devices. * * @return {@link HdmiPlaybackClient} instance. {@code null} on failure. */ @Nullable @SuppressLint("RequiresPermission") public HdmiPlaybackClient getPlaybackClient() { return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK); } /** * Gets an object that represents an HDMI-CEC logical device of type TV on the system. * *

Used to send HDMI control messages to other devices and manage them through * HDMI bus. It is also possible to communicate with other logical devices hosted in the same * system if the system is configured to host more than one type of HDMI-CEC logical devices. * * @return {@link HdmiTvClient} instance. {@code null} on failure. */ @Nullable @SuppressLint("RequiresPermission") public HdmiTvClient getTvClient() { return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV); } /** * Gets an object that represents an HDMI-CEC logical device of type audio system on the system. * *

Used to send HDMI control messages to other devices like TV through HDMI bus. It is also * possible to communicate with other logical devices hosted in the same system if the system is * configured to host more than one type of HDMI-CEC logical devices. * * @return {@link HdmiAudioSystemClient} instance. {@code null} on failure. * * @hide */ @Nullable @SuppressLint("RequiresPermission") public HdmiAudioSystemClient getAudioSystemClient() { return (HdmiAudioSystemClient) getClient(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); } /** * Gets an object that represents an HDMI-CEC logical device of type switch on the system. * *

Used to send HDMI control messages to other devices (e.g. TVs) through HDMI bus. * It is also possible to communicate with other logical devices hosted in the same * system if the system is configured to host more than one type of HDMI-CEC logical device. * * @return {@link HdmiSwitchClient} instance. {@code null} on failure. */ @Nullable @SuppressLint("RequiresPermission") public HdmiSwitchClient getSwitchClient() { return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH); } /** * Get a snapshot of the real-time status of the devices on the CEC bus. * * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices on the CEC bus. An * empty list will be returned if there is none. */ @NonNull public List getConnectedDevices() { try { return mService.getDeviceList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @removed * @deprecated Please use {@link #getConnectedDevices()} instead. */ @Deprecated public List getConnectedDevicesList() { try { return mService.getDeviceList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the list of the HDMI ports configuration. * *

This returns an empty list when the current device does not have HDMI ports. * * @return a list of {@link HdmiPortInfo} */ @NonNull public List getPortInfo() { try { return mService.getPortInfo(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Power off the target device by sending CEC commands. Note that this device can't be the * current device itself. * *

The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered off. */ public void powerOffDevice(@NonNull HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.powerOffRemoteDevice( deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @removed * @deprecated Please use {@link #powerOffDevice(deviceInfo)} instead. */ @Deprecated public void powerOffRemoteDevice(@NonNull HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.powerOffRemoteDevice( deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Power on the target device by sending CEC commands. Note that this device can't be the * current device itself. * *

The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered on. * * @hide */ public void powerOnDevice(HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.powerOnRemoteDevice( deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @removed * @deprecated Please use {@link #powerOnDevice(deviceInfo)} instead. */ @Deprecated public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.powerOnRemoteDevice( deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Request the target device to be the new Active Source by sending CEC commands. Note that * this device can't be the current device itself. * *

The target device info can be obtained by calling {@link #getConnectedDevicesList()}. * *

If the target device responds to the command, the users should see the target device * streaming on their TVs. * * @param deviceInfo HdmiDeviceInfo of the target device */ public void setActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @removed * @deprecated Please use {@link #setActiveSource(deviceInfo)} instead. */ @Deprecated public void requestRemoteDeviceToBecomeActiveSource(@NonNull HdmiDeviceInfo deviceInfo) { Objects.requireNonNull(deviceInfo); try { mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Controls standby mode of the system. It will also try to turn on/off the connected devices if * necessary. * * @param isStandbyModeOn target status of the system's standby mode */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean isStandbyModeOn) { try { mService.setStandbyMode(isStandbyModeOn); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * For CEC source devices (OTT/STB/Audio system): toggle the power status of the HDMI-connected * display and follow the display's new power status. * For all other devices: no functionality. * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void toggleAndFollowTvPower() { try { mService.toggleAndFollowTvPower(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Determines whether the HDMI CEC stack should handle KEYCODE_TV_POWER. * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public boolean shouldHandleTvPowerKey() { try { return mService.shouldHandleTvPowerKey(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Controls whether volume control commands via HDMI CEC are enabled. * *

When disabled: *

* *

Effects on different device types: * * * * * * * * * * * * * * * * *
HDMI CEC device typeenableddisabled
TV (type: 0)Per CEC specification.TV changes system volume. TV no longer reacts to incoming volume changes via * {@code }. TV no longer handles {@code } * .
Playback device (type: 4)Device sends volume commands to TV/Audio system via {@code }Device does not send volume commands via {@code }.
Audio device (type: 5)Full "System Audio Control" capabilities.Audio device no longer reacts to incoming {@code } * volume commands. Audio device no longer reports volume changes via {@code }.
* *

Due to the resulting behavior, usage on TV and Audio devices is discouraged. * * @param hdmiCecVolumeControlEnabled target state of HDMI CEC volume control. * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVolumeControlEnabled( @VolumeControl int hdmiCecVolumeControlEnabled) { try { mService.setCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE, hdmiCecVolumeControlEnabled); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Returns whether volume changes via HDMI CEC are enabled. * * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) @VolumeControl public int getHdmiCecVolumeControlEnabled() { try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Gets whether the system is in system audio mode. * * @hide */ public boolean getSystemAudioMode() { try { return mService.getSystemAudioMode(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the physical address of the device. * *

Physical address needs to be automatically adjusted when devices are phyiscally or * electrically added or removed from the device tree. Please see HDMI Specification Version * 1.4b 8.7 Physical Address for more details on the address discovery proccess. */ public int getPhysicalAddress() { return getLocalPhysicalAddress(); } /** * Check if the target device is connected to the current device. * *

The API also returns true if the current device is the target. * * @param targetDevice {@link HdmiDeviceInfo} of the target device. * @return true if {@code targetDevice} is directly or indirectly * connected to the current device. */ public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { Objects.requireNonNull(targetDevice); int physicalAddress = getLocalPhysicalAddress(); if (physicalAddress == INVALID_PHYSICAL_ADDRESS) { return false; } int targetPhysicalAddress = targetDevice.getPhysicalAddress(); if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { return false; } return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress) != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE; } /** * @removed * @deprecated Please use {@link #isDeviceConnected(targetDevice)} instead. */ @Deprecated public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) { Objects.requireNonNull(targetDevice); int physicalAddress = getLocalPhysicalAddress(); if (physicalAddress == INVALID_PHYSICAL_ADDRESS) { return false; } int targetPhysicalAddress = targetDevice.getPhysicalAddress(); if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { return false; } return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress) != HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE; } /** * Listener used to get hotplug event from HDMI port. */ public interface HotplugEventListener { void onReceived(HdmiHotplugEvent event); } private final ArrayMap mHotplugEventListeners = new ArrayMap<>(); /** * Listener used to get HDMI Control (CEC) status (enabled/disabled) and the connected display * status. * @hide */ public interface HdmiControlStatusChangeListener { /** * Called when HDMI Control (CEC) is enabled/disabled. * * @param isCecEnabled status of HDMI Control * {@link android.hardware.hdmi.HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_ENABLED}: * {@code HDMI_CEC_CONTROL_ENABLED} if enabled. * @param isCecAvailable status of CEC support of the connected display (the TV). * {@code true} if supported. * * Note: Value of isCecAvailable is only valid when isCecEnabled is true. **/ void onStatusChange(@HdmiControlManager.HdmiCecControl int isCecEnabled, boolean isCecAvailable); } private final ArrayMap mHdmiControlStatusChangeListeners = new ArrayMap<>(); /** * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled). * @hide */ public interface HdmiCecVolumeControlFeatureListener { /** * Called when the HDMI Control (CEC) volume control feature is enabled/disabled. * * @param hdmiCecVolumeControl status of HDMI CEC volume control feature * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(int)} ()} **/ void onHdmiCecVolumeControlFeature(@VolumeControl int hdmiCecVolumeControl); } private final ArrayMap mHdmiCecVolumeControlFeatureListeners = new ArrayMap<>(); /** * Listener used to get vendor-specific commands. */ public interface VendorCommandListener { /** * Called when a vendor command is received. * * @param srcAddress source logical address * @param destAddress destination logical address * @param params vendor-specific parameters * @param hasVendorId {@code true} if the command is <Vendor Command * With ID>. The first 3 bytes of params is vendor id. */ void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId); /** * The callback is called: *

* The client shouldn't hold the thread too long since this is a blocking call. * * @param enabled {@code true} if HdmiControlService is enabled. * @param reason the reason code why the state of HdmiControlService is changed. * @see #CONTROL_STATE_CHANGED_REASON_START * @see #CONTROL_STATE_CHANGED_REASON_SETTING * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP * @see #CONTROL_STATE_CHANGED_REASON_STANDBY */ void onControlStateChanged(boolean enabled, int reason); } /** * Adds a listener to get informed of {@link HdmiHotplugEvent}. * *

To stop getting the notification, * use {@link #removeHotplugEventListener(HotplugEventListener)}. * * Note that each invocation of the callback will be executed on an arbitrary * Binder thread. This means that all callback implementations must be * thread safe. To specify the execution thread, use * {@link addHotplugEventListener(Executor, HotplugEventListener)}. * * @param listener {@link HotplugEventListener} instance * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener) */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(HotplugEventListener listener) { addHotplugEventListener(ConcurrentUtils.DIRECT_EXECUTOR, listener); } /** * Adds a listener to get informed of {@link HdmiHotplugEvent}. * *

To stop getting the notification, * use {@link #removeHotplugEventListener(HotplugEventListener)}. * * @param listener {@link HotplugEventListener} instance * @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener) */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(@NonNull @CallbackExecutor Executor executor, @NonNull HotplugEventListener listener) { if (mService == null) { Log.e(TAG, "addHotplugEventListener: HdmiControlService is not available"); return; } if (mHotplugEventListeners.containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiHotplugEventListener wrappedListener = getHotplugEventListenerWrapper(executor, listener); mHotplugEventListeners.put(listener, wrappedListener); try { mService.addHotplugEventListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Removes a listener to stop getting informed of {@link HdmiHotplugEvent}. * * @param listener {@link HotplugEventListener} instance to be removed */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(HotplugEventListener listener) { if (mService == null) { Log.e(TAG, "removeHotplugEventListener: HdmiControlService is not available"); return; } IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeHotplugEventListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiHotplugEventListener getHotplugEventListenerWrapper( Executor executor, final HotplugEventListener listener) { return new IHdmiHotplugEventListener.Stub() { @Override public void onReceived(HdmiHotplugEvent event) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> listener.onReceived(event)); } finally { Binder.restoreCallingIdentity(token); } } }; } /** * Adds a listener to get informed of {@link HdmiControlStatusChange}. * *

To stop getting the notification, * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}. * * Note that each invocation of the callback will be executed on an arbitrary * Binder thread. This means that all callback implementations must be * thread safe. To specify the execution thread, use * {@link addHdmiControlStatusChangeListener(Executor, HdmiControlStatusChangeListener)}. * * @param listener {@link HdmiControlStatusChangeListener} instance * @see HdmiControlManager#removeHdmiControlStatusChangeListener( * HdmiControlStatusChangeListener) * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { addHdmiControlStatusChangeListener(ConcurrentUtils.DIRECT_EXECUTOR, listener); } /** * Adds a listener to get informed of {@link HdmiControlStatusChange}. * *

To stop getting the notification, * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}. * * @param listener {@link HdmiControlStatusChangeListener} instance * @see HdmiControlManager#removeHdmiControlStatusChangeListener( * HdmiControlStatusChangeListener) * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiControlStatusChangeListener(@NonNull @CallbackExecutor Executor executor, @NonNull HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "addHdmiControlStatusChangeListener: HdmiControlService is not available"); return; } if (mHdmiControlStatusChangeListeners.containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiControlStatusChangeListener wrappedListener = getHdmiControlStatusChangeListenerWrapper(executor, listener); mHdmiControlStatusChangeListeners.put(listener, wrappedListener); try { mService.addHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Removes a listener to stop getting informed of {@link HdmiControlStatusChange}. * * @param listener {@link HdmiControlStatusChangeListener} instance to be removed * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "removeHdmiControlStatusChangeListener: HdmiControlService is not available"); return; } IHdmiControlStatusChangeListener wrappedListener = mHdmiControlStatusChangeListeners.remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiControlStatusChangeListener getHdmiControlStatusChangeListenerWrapper( Executor executor, final HdmiControlStatusChangeListener listener) { return new IHdmiControlStatusChangeListener.Stub() { @Override public void onStatusChange(@HdmiCecControl int isCecEnabled, boolean isCecAvailable) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> listener.onStatusChange(isCecEnabled, isCecAvailable)); } finally { Binder.restoreCallingIdentity(token); } } }; } /** * Adds a listener to get informed of changes to the state of the HDMI CEC volume control * feature. * * Upon adding a listener, the current state of the HDMI CEC volume control feature will be * sent immediately. * *

To stop getting the notification, * use {@link #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)}. * * @param listener {@link HdmiCecVolumeControlFeatureListener} instance * @hide * @see #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener) */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor, @NonNull HdmiCecVolumeControlFeatureListener listener) { if (mService == null) { Log.e(TAG, "addHdmiCecVolumeControlFeatureListener: HdmiControlService is not available"); return; } if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiCecVolumeControlFeatureListener wrappedListener = createHdmiCecVolumeControlFeatureListenerWrapper(executor, listener); mHdmiCecVolumeControlFeatureListeners.put(listener, wrappedListener); try { mService.addHdmiCecVolumeControlFeatureListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Removes a listener to stop getting informed of changes to the state of the HDMI CEC volume * control feature. * * @param listener {@link HdmiCecVolumeControlFeatureListener} instance to be removed * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiCecVolumeControlFeatureListener( HdmiCecVolumeControlFeatureListener listener) { if (mService == null) { Log.e(TAG, "removeHdmiCecVolumeControlFeatureListener: HdmiControlService is not " + "available"); return; } IHdmiCecVolumeControlFeatureListener wrappedListener = mHdmiCecVolumeControlFeatureListeners.remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeHdmiCecVolumeControlFeatureListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiCecVolumeControlFeatureListener createHdmiCecVolumeControlFeatureListenerWrapper( Executor executor, final HdmiCecVolumeControlFeatureListener listener) { return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() { @Override public void onHdmiCecVolumeControlFeature(int enabled) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled)); } finally { Binder.restoreCallingIdentity(token); } } }; } /** * Listener used to get setting change notification. */ public interface CecSettingChangeListener { /** * Called when value of a setting changes. * * @param setting name of a CEC setting that changed */ void onChange(@NonNull @SettingName String setting); } private final ArrayMap> mCecSettingChangeListeners = new ArrayMap<>(); private void addCecSettingChangeListener( @NonNull @SettingName String setting, @NonNull @CallbackExecutor Executor executor, @NonNull CecSettingChangeListener listener) { if (mService == null) { Log.e(TAG, "addCecSettingChangeListener: HdmiControlService is not available"); return; } if (mCecSettingChangeListeners.containsKey(setting) && mCecSettingChangeListeners.get(setting).containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiCecSettingChangeListener wrappedListener = getCecSettingChangeListenerWrapper(executor, listener); if (!mCecSettingChangeListeners.containsKey(setting)) { mCecSettingChangeListeners.put(setting, new ArrayMap<>()); } mCecSettingChangeListeners.get(setting).put(listener, wrappedListener); try { mService.addCecSettingChangeListener(setting, wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private void removeCecSettingChangeListener( @NonNull @SettingName String setting, @NonNull CecSettingChangeListener listener) { if (mService == null) { Log.e(TAG, "removeCecSettingChangeListener: HdmiControlService is not available"); return; } IHdmiCecSettingChangeListener wrappedListener = !mCecSettingChangeListeners.containsKey(setting) ? null : mCecSettingChangeListeners.get(setting).remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeCecSettingChangeListener(setting, wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiCecSettingChangeListener getCecSettingChangeListenerWrapper( Executor executor, final CecSettingChangeListener listener) { return new IHdmiCecSettingChangeListener.Stub() { @Override public void onChange(String setting) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> listener.onChange(setting)); } finally { Binder.restoreCallingIdentity(token); } } }; } /** * Get a set of user-modifiable HDMI control settings. * This applies to CEC settings and eARC settings. * * @return a set of user-modifiable settings. * @throws RuntimeException when the HdmiControlService is not available. */ // TODO(b/240379115): rename this API to represent that this applies to all HDMI control // settings and not just CEC settings. @NonNull @SettingName @RequiresPermission(android.Manifest.permission.HDMI_CEC) public List getUserCecSettings() { if (mService == null) { Log.e(TAG, "getUserCecSettings: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getUserCecSettings(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get a set of allowed values for an HDMI control setting (string value-type). * This applies to CEC settings and eARC settings. * * * @param name name of the setting * @return a set of allowed values for a settings. {@code null} on failure. * @throws IllegalArgumentException when setting {@code name} does not exist. * @throws IllegalArgumentException when setting {@code name} value type is invalid. * @throws RuntimeException when the HdmiControlService is not available. */ // TODO(b/240379115): rename this API to represent that this applies to all HDMI control // settings and not just CEC settings. @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public List getAllowedCecSettingStringValues(@NonNull @SettingName String name) { if (mService == null) { Log.e(TAG, "getAllowedCecSettingStringValues: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getAllowedCecSettingStringValues(name); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get a set of allowed values for an HDMI control setting (int value-type). * This applies to CEC settings and eARC settings. * * @param name name of the setting * @return a set of allowed values for a settings. {@code null} on failure. * @throws IllegalArgumentException when setting {@code name} does not exist. * @throws IllegalArgumentException when setting {@code name} value type is invalid. * @throws RuntimeException when the HdmiControlService is not available. */ // TODO(b/240379115): rename this API to represent that this applies to all HDMI control // settings and not just CEC settings. @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public List getAllowedCecSettingIntValues(@NonNull @SettingName String name) { if (mService == null) { Log.e(TAG, "getAllowedCecSettingIntValues: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { int[] allowedValues = mService.getAllowedCecSettingIntValues(name); return Arrays.stream(allowedValues).boxed().collect(Collectors.toList()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the global status of HDMI CEC. * *

This allows to enable/disable HDMI CEC on the device. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecEnabled(@NonNull @HdmiCecControl int value) { if (mService == null) { Log.e(TAG, "setHdmiCecEnabled: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current global status of HDMI CEC. * *

Reflects whether HDMI CEC is currently enabled on the device. */ @NonNull @HdmiCecControl @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecEnabled() { if (mService == null) { Log.e(TAG, "getHdmiCecEnabled: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Add change listener for global status of HDMI CEC. * *

To stop getting the notification, * use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}. * * Note that each invocation of the callback will be executed on an arbitrary * Binder thread. This means that all callback implementations must be * thread safe. To specify the execution thread, use * {@link addHdmiCecEnabledChangeListener(Executor, CecSettingChangeListener)}. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener(@NonNull CecSettingChangeListener listener) { addHdmiCecEnabledChangeListener(ConcurrentUtils.DIRECT_EXECUTOR, listener); } /** * Add change listener for global status of HDMI CEC. * *

To stop getting the notification, * use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener( @NonNull @CallbackExecutor Executor executor, @NonNull CecSettingChangeListener listener) { addCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, executor, listener); } /** * Remove change listener for global status of HDMI CEC. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiCecEnabledChangeListener( @NonNull CecSettingChangeListener listener) { removeCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, listener); } /** * Set the version of the HDMI CEC specification currently used. * *

Allows to select either CEC 1.4b or 2.0 to be used by the device. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVersion(@NonNull @HdmiCecVersion int value) { if (mService == null) { Log.e(TAG, "setHdmiCecVersion: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the version of the HDMI CEC specification currently used. * *

Reflects which CEC version 1.4b or 2.0 is currently used by the device. * * @see HdmiControlManager#CEC_SETTING_NAME_HDMI_CEC_VERSION */ @NonNull @HdmiCecVersion @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecVersion() { if (mService == null) { Log.e(TAG, "getHdmiCecVersion: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the status of Routing Control feature. * *

This allows to enable/disable Routing Control on the device. * If enabled, the switch device will route to the correct input source on * receiving Routing Control related messages. If disabled, you can only * switch the input via controls on this device. * * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setRoutingControl(@NonNull @RoutingControl int value) { if (mService == null) { Log.e(TAG, "setRoutingControl: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of Routing Control feature. * *

Reflects whether Routing Control is currently enabled on the device. * If enabled, the switch device will route to the correct input source on * receiving Routing Control related messages. If disabled, you can only * switch the input via controls on this device. * * @see HdmiControlManager#CEC_SETTING_NAME_ROUTING_CONTROL */ @NonNull @RoutingControl @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getRoutingControl() { if (mService == null) { Log.e(TAG, "getRoutingControl: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_ROUTING_CONTROL); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the status of Soundbar mode feature. * *

This allows to enable/disable Soundbar mode on the playback device. * The setting's effect will be available on devices where the hardware supports this feature. * If enabled, an audio system local device will be allocated and try to establish an ARC * connection with the TV. If disabled, the ARC connection will be terminated and the audio * system local device will be removed from the network. * * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSoundbarMode(@SoundbarMode int value) { if (mService == null) { Log.e(TAG, "setSoundbarMode: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of Soundbar mode feature. * *

Reflects whether Soundbar mode is currently enabled on the playback device. * If enabled, an audio system local device will be allocated and try to establish an ARC * connection with the TV. If disabled, the ARC connection will be terminated and the audio * system local device will be removed from the network. * * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE */ @SoundbarMode @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSoundbarMode() { if (mService == null) { Log.e(TAG, "getSoundbarMode: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the status of Power Control. * *

Specifies to which devices Power Control messages should be sent: * only to the TV, broadcast to all devices, no power control messages. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerControlMode(@NonNull @PowerControlMode String value) { if (mService == null) { Log.e(TAG, "setPowerControlMode: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the status of Power Control. * *

Reflects to which devices Power Control messages should be sent: * only to the TV, broadcast to all devices, no power control messages. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_CONTROL_MODE */ @NonNull @PowerControlMode @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerControlMode() { if (mService == null) { Log.e(TAG, "getPowerControlMode: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the current power state behaviour when Active Source is lost. * *

Sets the action taken: do nothing or go to sleep immediately. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setPowerStateChangeOnActiveSourceLost( @NonNull @ActiveSourceLostBehavior String value) { if (mService == null) { Log.e(TAG, "setPowerStateChangeOnActiveSourceLost: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingStringValue( CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current power state behaviour when Active Source is lost. * *

Reflects the action taken: do nothing or go to sleep immediately. * * @see HdmiControlManager#CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST */ @NonNull @ActiveSourceLostBehavior @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerStateChangeOnActiveSourceLost() { if (mService == null) { Log.e(TAG, "getPowerStateChangeOnActiveSourceLost: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingStringValue( CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the current status of System Audio Control. * *

Sets whether HDMI System Audio Control feature is enabled. If enabled, * TV or Audio System will try to turn on the System Audio Mode if there's a * connected CEC-enabled AV Receiver. Then an audio stream will be played on * the AVR instead of TV speaker or Audio System speakers. If disabled, the * System Audio Mode will never be activated. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioControl(@NonNull @SystemAudioControl int value) { if (mService == null) { Log.e(TAG, "setSystemAudioControl: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of System Audio Control. * *

Reflects whether HDMI System Audio Control feature is enabled. If enabled, * TV or Audio System will try to turn on the System Audio Mode if there's a * connected CEC-enabled AV Receiver. Then an audio stream will be played on * the AVR instead of TV speaker or Audio System speakers. If disabled, the * System Audio Mode will never be activated. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL */ @NonNull @SystemAudioControl @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioControl() { if (mService == null) { Log.e(TAG, "getSystemAudioControl: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the current status of System Audio Mode muting. * *

Sets whether the device should be muted when System Audio Mode is turned off. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting int value) { if (mService == null) { Log.e(TAG, "setSystemAudioModeMuting: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of System Audio Mode muting. * *

Reflects whether the device should be muted when System Audio Mode is turned off. * * @see HdmiControlManager#CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING */ @NonNull @SystemAudioModeMuting @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioModeMuting() { if (mService == null) { Log.e(TAG, "getSystemAudioModeMuting: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the current status of TV Wake on One Touch Play. * *

Sets whether the TV should wake up upon reception of <Text View On> * or <Image View On>. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvWakeOnOneTouchPlay(@NonNull @TvWakeOnOneTouchPlay int value) { if (mService == null) { Log.e(TAG, "setTvWakeOnOneTouchPlay: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of TV Wake on One Touch Play. * *

Reflects whether the TV should wake up upon reception of <Text View On> * or <Image View On>. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY */ @NonNull @TvWakeOnOneTouchPlay @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getTvWakeOnOneTouchPlay() { if (mService == null) { Log.e(TAG, "getTvWakeOnOneTouchPlay: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the current status of TV send <Standby> on Sleep. * *

Sets whether the device will also turn off other CEC devices * when it goes to standby mode. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setTvSendStandbyOnSleep(@NonNull @TvSendStandbyOnSleep int value) { if (mService == null) { Log.e(TAG, "setTvSendStandbyOnSleep: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current status of TV send <Standby> on Sleep. * *

Reflects whether the device will also turn off other CEC devices * when it goes to standby mode. * * @see HdmiControlManager#CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP */ @NonNull @TvSendStandbyOnSleep @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getTvSendStandbyOnSleep() { if (mService == null) { Log.e(TAG, "getTvSendStandbyOnSleep: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set presence of one Short Audio Descriptor (SAD) in the query. * *

Allows the caller to specify whether the SAD for a specific audio codec should be * present in the <Request Short Audio Descriptor> query. Each <Request Short Audio * Descriptor> message can carry at most 4 SADs at a time. This method allows the caller to * limit the amount of SADs queried and therefore limit the amount of CEC messages on the bus. * *

When an ARC connection is established, the TV sends a * <Request Short Audio Descriptor> query to the Audio System that it's connected to. If * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send * audio in that format to be output on the Audio System via ARC. * If a codec is not queried, the TV doesn't know if the connected Audio System supports this * SAD and doesn't send audio in that format to the Audio System. * * @param setting SAD to set. * @param value Presence to set the SAD to. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSadPresenceInQuery(@NonNull @CecSettingSad String setting, @SadPresenceInQuery int value) { if (mService == null) { Log.e(TAG, "setSadPresenceInQuery: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(setting, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set presence of multiple Short Audio Descriptors (SADs) in the query. * *

Allows the caller to specify whether the SADs for specific audio codecs should be present * in the <Request Short Audio Descriptor> query. For audio codecs that are not specified, * the SAD's presence remains at its previous value. Each <Request Short Audio Descriptor> * message can carry at most 4 SADs at a time. This method allows the caller to limit the amount * of SADs queried and therefore limit the amount of CEC messages on the bus. * *

When an ARC connection is established, the TV sends a * <Request Short Audio Descriptor> query to the Audio System that it's connected to. If * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send * audio in that format to be output on the Audio System via ARC. * If a codec is not queried, the TV doesn't know if the connected Audio System supports this * SAD and doesn't send audio in that format to the Audio System. * * * @param settings SADs to set. * @param value Presence to set all specified SADs to. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSadsPresenceInQuery(@NonNull @CecSettingSad List settings, @SadPresenceInQuery int value) { if (mService == null) { Log.e(TAG, "setSadsPresenceInQuery: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { for (String sad : settings) { mService.setCecSettingIntValue(sad, value); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get presence of one Short Audio Descriptor (SAD) in the query. * *

Reflects whether the SAD for a specific audio codec should be present in the * <Request Short Audio Descriptor> query. * *

When an ARC connection is established, the TV sends a * <Request Short Audio Descriptor> query to the Audio System that it's connected to. If * an SAD is queried and the Audio System reports that it supports that SAD, the TV can send * audio in that format to be output on the Audio System via ARC. * If a codec is not queried, the TV doesn't know if the connected Audio System supports this * SAD and doesn't send audio in that format to the Audio System. * * @param setting SAD to get. * @return Current presence of the specified SAD. */ @SadPresenceInQuery @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSadPresenceInQuery(@NonNull @CecSettingSad String setting) { if (mService == null) { Log.e(TAG, "getSadPresenceInQuery: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(setting); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set the global status of eARC. * *

This allows to enable/disable the eARC feature on the device. If the feature is enabled * and the hardware supports eARC as well, the device can attempt to establish an eARC * connection. */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setEarcEnabled(@NonNull @EarcFeature int value) { if (mService == null) { Log.e(TAG, "setEarcEnabled: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { mService.setCecSettingIntValue(SETTING_NAME_EARC_ENABLED, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Get the current global status of eARC. * *

Reflects whether the eARC feature is currently enabled on the device. */ @NonNull @EarcFeature @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getEarcEnabled() { if (mService == null) { Log.e(TAG, "getEarcEnabled: HdmiControlService is not available"); throw new RuntimeException("HdmiControlService is not available"); } try { return mService.getCecSettingIntValue(SETTING_NAME_EARC_ENABLED); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }