Merge "Unhide APIs of Android HDMI Framework for Q."
diff --git a/api/system-current.txt b/api/system-current.txt
index f187439..49abe28 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1853,9 +1853,15 @@
public final class HdmiControlManager {
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
method @Nullable public android.hardware.hdmi.HdmiClient getClient(int);
+ method @Nullable public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList();
+ method public int getPhysicalAddress();
method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+ method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient();
+ method public boolean isRemoteDeviceConnected(android.hardware.hdmi.HdmiDeviceInfo);
+ method public void powerOffRemoteDevice(android.hardware.hdmi.HdmiDeviceInfo);
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
+ method public void requestRemoteDeviceToBecomeActiveSource(android.hardware.hdmi.HdmiDeviceInfo);
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
field public static final int AVR_VOLUME_MUTED = 101; // 0x65
@@ -1945,6 +1951,9 @@
field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
}
+ @IntDef({android.hardware.hdmi.HdmiControlManager.RESULT_SUCCESS, android.hardware.hdmi.HdmiControlManager.RESULT_TIMEOUT, android.hardware.hdmi.HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_ALREADY_IN_PROGRESS, android.hardware.hdmi.HdmiControlManager.RESULT_EXCEPTION, android.hardware.hdmi.HdmiControlManager.RESULT_INCORRECT_MODE, android.hardware.hdmi.HdmiControlManager.RESULT_COMMUNICATION_FAILED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface HdmiControlManager.ControlCallbackResult {
+ }
+
public static interface HdmiControlManager.HotplugEventListener {
method public void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
}
@@ -2071,6 +2080,16 @@
public abstract static class HdmiRecordSources.RecordSource {
}
+ public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient {
+ method public int getDeviceType();
+ method public void selectPort(int, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
+ method public void selectPort(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
+ }
+
+ public static interface HdmiSwitchClient.OnSelectListener {
+ method public void onSelect(@android.hardware.hdmi.HdmiControlManager.ControlCallbackResult int);
+ }
+
public class HdmiTimerRecordSources {
method public static boolean checkTimerRecordSource(int, byte[]);
method public static android.hardware.hdmi.HdmiTimerRecordSources.Duration durationOf(int, int);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index a98b31a..56020b2 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -18,6 +18,7 @@
import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -33,6 +34,8 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.List;
/**
@@ -106,9 +109,24 @@
public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
+ @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,
+ })
+ 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;
@@ -394,16 +412,15 @@
/**
* Gets an object that represents an HDMI-CEC logical device of type switch on the system.
*
- * <p>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.
+ * <p>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.
- *
- * TODO(b/110094868): unhide for Q
* @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiSwitchClient getSwitchClient() {
return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
@@ -412,11 +429,15 @@
/**
* Get a snapshot of the real-time status of the remote devices.
*
- * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
+ * <p>This only applies to devices with multiple HDMI inputs.
*
- * TODO(b/110094868): unhide for Q
+ * @return a list of {@link HdmiDeviceInfo} of the connected CEC devices. An empty
+ * list will be returned if there is none.
+ *
* @hide
*/
+ @SystemApi
+ @Nullable
public List<HdmiDeviceInfo> getConnectedDevicesList() {
try {
return mService.getDeviceList();
@@ -426,14 +447,17 @@
}
/**
- * Power off the target device.
+ * Power off the target device by sending CEC commands.
*
- * @param deviceInfo HdmiDeviceInfo of the device to be powered off
+ * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
*
- * TODO(b/110094868): unhide for Q
+ * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered off.
+ *
* @hide
*/
+ @SystemApi
public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
+ Preconditions.checkNotNull(deviceInfo);
try {
mService.powerOffRemoteDevice(
deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
@@ -443,14 +467,16 @@
}
/**
- * Power on the target device.
+ * Power on the target device by sending CEC commands.
*
- * @param deviceInfo HdmiDeviceInfo of the device to be powered on
+ * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
*
- * TODO(b/110094868): unhide for Q
+ * @param deviceInfo {@link HdmiDeviceInfo} of the device to be powered on.
+ *
* @hide
*/
public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
+ Preconditions.checkNotNull(deviceInfo);
try {
mService.powerOnRemoteDevice(
deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
@@ -460,14 +486,17 @@
}
/**
- * Ask the target device to be the new Active Source.
+ * Request the target device to be the new Active Source by sending CEC commands.
+ *
+ * <p>The target device info can be obtained by calling {@link #getConnectedDevicesList()}.
*
* @param deviceInfo HdmiDeviceInfo of the target device
*
- * TODO(b/110094868): unhide for Q
* @hide
*/
- public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+ @SystemApi
+ public void requestRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
+ Preconditions.checkNotNull(deviceInfo);
try {
mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
} catch (RemoteException e) {
@@ -506,8 +535,13 @@
/**
* Get the physical address of the device.
*
+ * <p>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.
+ *
* @hide
*/
+ @SystemApi
public int getPhysicalAddress() {
if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
return mPhysicalAddress;
@@ -521,16 +555,19 @@
}
/**
- * Check if the target device is connected to the current device. The
- * API also returns true if the current device is the target.
+ * Check if the target remote device is connected to the current device.
+ *
+ * <p>The API also returns true if the current device is the target.
*
* @param targetDevice {@link HdmiDeviceInfo} of the target device.
- * @return true if {@code device} is directly or indirectly connected to the
+ * @return true if {@code targetDevice} is directly or indirectly
+ * connected to the current device.
*
- * TODO(b/110094868): unhide for Q
* @hide
*/
- public boolean isTargetDeviceConnected(HdmiDeviceInfo targetDevice) {
+ @SystemApi
+ public boolean isRemoteDeviceConnected(HdmiDeviceInfo targetDevice) {
+ Preconditions.checkNotNull(targetDevice);
mPhysicalAddress = getPhysicalAddress();
if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index 1ac2973..a036512 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -15,24 +15,30 @@
*/
package android.hardware.hdmi;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.hdmi.HdmiControlManager.ControlCallbackResult;
+import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
/**
- * HdmiSwitchClient represents HDMI-CEC logical device of type Switch in the Android system which
- * acts as switch.
+ * An {@code HdmiSwitchClient} represents a HDMI-CEC switch device.
*
- * <p>HdmiSwitchClient has a CEC device type of HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH,
- * but it is used by all Android TV devices that have multiple HDMI inputs,
- * even if it is not a "pure" swicth and has another device type like TV or Player.
+ * <p>HdmiSwitchClient has a CEC device type of HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH, but it is
+ * used by all Android devices that have multiple HDMI inputs, even if it is not a "pure" swicth
+ * and has another device type like TV or Player.
*
* @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
*/
+@SystemApi
public class HdmiSwitchClient extends HdmiClient {
private static final String TAG = "HdmiSwitchClient";
@@ -41,17 +47,15 @@
super(service);
}
- private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+ private static IHdmiControlCallback getCallbackWrapper(final OnSelectListener listener) {
return new IHdmiControlCallback.Stub() {
@Override
public void onComplete(int result) {
- callback.onComplete(result);
+ listener.onSelect(result);
}
};
}
- /** @hide */
- // TODO(b/110094868): unhide for Q
@Override
public int getDeviceType() {
return HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH;
@@ -61,20 +65,17 @@
* Selects a CEC logical device to be a new active source.
*
* @param logicalAddress logical address of the device to select
- * @param callback callback to get the result with
- * @throws {@link IllegalArgumentException} if the {@code callback} is null
+ * @param listener listener to get the result with
*
* @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
*/
- public void deviceSelect(int logicalAddress, @NonNull SelectCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null.");
- }
+ public void selectDevice(int logicalAddress, @NonNull OnSelectListener listener) {
+ Preconditions.checkNotNull(listener);
try {
- mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+ mService.deviceSelect(logicalAddress, getCallbackWrapper(listener));
} catch (RemoteException e) {
Log.e(TAG, "failed to select device: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -82,20 +83,83 @@
* Selects a HDMI port to be a new route path.
*
* @param portId HDMI port to select
- * @param callback callback to get the result with
- * @throws {@link IllegalArgumentException} if the {@code callback} is null
+ * @see {@link android.media.tv.TvInputHardwareInfo#getHdmiPortId()}
+ * to get portId of a specific TV Input.
+ * @param listener listener to get the result with
*
* @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
*/
- public void portSelect(int portId, @NonNull SelectCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("Callback must not be null");
- }
+ @SystemApi
+ public void selectPort(int portId, @NonNull OnSelectListener listener) {
+ Preconditions.checkNotNull(listener);
try {
- mService.portSelect(portId, getCallbackWrapper(callback));
+ mService.portSelect(portId, getCallbackWrapper(listener));
} catch (RemoteException e) {
Log.e(TAG, "failed to select port: ", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Selects a CEC logical device to be a new active source.
+ *
+ * @param logicalAddress logical address of the device to select
+ * @param executor executor to allow the develper to specify the thread upon which the listeners
+ * will be invoked
+ * @param listener listener to get the result with
+ *
+ * @hide
+ */
+ public void selectDevice(
+ int logicalAddress,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnSelectListener listener) {
+ Preconditions.checkNotNull(listener);
+ try {
+ mService.deviceSelect(logicalAddress,
+ new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ Binder.withCleanCallingIdentity(
+ () -> executor.execute(() -> listener.onSelect(result)));
+ }
+ }
+ );
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to select device: ", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Selects a HDMI port to be a new route path.
+ *
+ * @param portId HDMI port to select
+ * @param executor executor to allow the develper to specify the thread upon which the listeners
+ * will be invoked
+ * @param listener listener to get the result with
+ *
+ * @hide
+ */
+ @SystemApi
+ public void selectPort(
+ int portId,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnSelectListener listener) {
+ Preconditions.checkNotNull(listener);
+ try {
+ mService.portSelect(portId,
+ new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ Binder.withCleanCallingIdentity(
+ () -> executor.execute(() -> listener.onSelect(result)));
+ }
+ }
+ );
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to select port: ", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -105,10 +169,9 @@
* <p>This only applies to device with multiple HDMI inputs
*
* @return list of {@link HdmiDeviceInfo} for connected CEC devices. Empty list is returned if
- * there is none.
+ * there is none.
*
* @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
*/
public List<HdmiDeviceInfo> getDeviceList() {
try {
@@ -120,18 +183,19 @@
}
/**
- * Callback interface used to get the result of {@link #deviceSelect} or {@link #portSelect}.
+ * Listener interface used to get the result of {@link #deviceSelect} or {@link #portSelect}.
*
* @hide
- * TODO(b/110094868): unhide and add @SystemApi for Q
*/
- public interface SelectCallback {
+ @SystemApi
+ public interface OnSelectListener {
/**
* Called when the operation is finished.
*
- * @param result the result value of {@link #deviceSelect} or {@link #portSelect}.
+ * @param result callback result.
+ * @see {@link ControlCallbackResult}
*/
- void onComplete(int result);
+ void onSelect(@ControlCallbackResult int result);
}
}