From eacebb90f675e2e84f723004697f823ced1e3602 Mon Sep 17 00:00:00 2001 From: Michal Olech Date: Tue, 30 Jun 2020 14:28:36 +0200 Subject: [PATCH] CEC: Add @CallbackExecutor to HdmiControlManager Listener methods API guidelines recommend adding ability to set the executor Bug: 156046799 Test: atest HdmiControlServiceTest Change-Id: I1f6dde6efc498a112ac7da2c61c36fcc2afa6638 --- api/system-current.txt | 1 + .../hardware/hdmi/HdmiControlManager.java | 64 +++++++++++++++++-- non-updatable-api/system-current.txt | 1 + 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index e931fe432ba4b..5aec63396ff6f 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2525,6 +2525,7 @@ package android.hardware.hdmi { public final class HdmiControlManager { method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.HotplugEventListener); method @Nullable public android.hardware.hdmi.HdmiClient getClient(int); method @NonNull public java.util.List getConnectedDevices(); method public int getPhysicalAddress(); diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index fc88f1e3062f7..2579ee687827a 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -37,6 +37,7 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ConcurrentUtils; import java.util.ArrayList; import java.util.List; @@ -891,6 +892,11 @@ public final class HdmiControlManager { *

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) * @@ -899,6 +905,24 @@ public final class HdmiControlManager { @SystemApi @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) + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.HDMI_CEC) + public void addHotplugEventListener(@NonNull @CallbackExecutor Executor executor, + @NonNull HotplugEventListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; @@ -907,7 +931,8 @@ public final class HdmiControlManager { Log.e(TAG, "listener is already registered"); return; } - IHdmiHotplugEventListener wrappedListener = getHotplugEventListenerWrapper(listener); + IHdmiHotplugEventListener wrappedListener = + getHotplugEventListenerWrapper(executor, listener); mHotplugEventListeners.put(listener, wrappedListener); try { mService.addHotplugEventListener(wrappedListener); @@ -943,15 +968,38 @@ public final class HdmiControlManager { } private IHdmiHotplugEventListener getHotplugEventListenerWrapper( - final HotplugEventListener listener) { + Executor executor, final HotplugEventListener listener) { return new IHdmiHotplugEventListener.Stub() { @Override public void onReceived(HdmiHotplugEvent event) { - listener.onReceived(event);; + Binder.clearCallingIdentity(); + executor.execute(() -> listener.onReceived(event)); } }; } + /** + * 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}. * @@ -965,7 +1013,8 @@ public final class HdmiControlManager { * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) - public void addHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { + public void addHdmiControlStatusChangeListener(@NonNull @CallbackExecutor Executor executor, + @NonNull HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; @@ -975,7 +1024,7 @@ public final class HdmiControlManager { return; } IHdmiControlStatusChangeListener wrappedListener = - getHdmiControlStatusChangeListenerWrapper(listener); + getHdmiControlStatusChangeListenerWrapper(executor, listener); mHdmiControlStatusChangeListeners.put(listener, wrappedListener); try { mService.addHdmiControlStatusChangeListener(wrappedListener); @@ -1011,11 +1060,12 @@ public final class HdmiControlManager { } private IHdmiControlStatusChangeListener getHdmiControlStatusChangeListenerWrapper( - final HdmiControlStatusChangeListener listener) { + Executor executor, final HdmiControlStatusChangeListener listener) { return new IHdmiControlStatusChangeListener.Stub() { @Override public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) { - listener.onStatusChange(isCecEnabled, isCecAvailable); + Binder.clearCallingIdentity(); + executor.execute(() -> listener.onStatusChange(isCecEnabled, isCecAvailable)); } }; } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 53499f8165a21..e3aceecc113d8 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -2465,6 +2465,7 @@ package android.hardware.hdmi { public final class HdmiControlManager { method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener); + method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.HotplugEventListener); method @Nullable public android.hardware.hdmi.HdmiClient getClient(int); method @NonNull public java.util.List getConnectedDevices(); method public int getPhysicalAddress();