diff --git a/core/api/current.txt b/core/api/current.txt index 2c085b4241e60..99065b78cb2ba 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18344,8 +18344,8 @@ package android.hardware.display { } public final class DisplayManager { - method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int); - method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, int, int, int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler); + method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int); + method public android.hardware.display.VirtualDisplay createVirtualDisplay(@NonNull String, @IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable android.hardware.display.VirtualDisplay.Callback, @Nullable android.os.Handler); method public android.view.Display getDisplay(int); method public android.view.Display[] getDisplays(); method public android.view.Display[] getDisplays(String); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 1adaf4b82ea78..c1f47f1d2a488 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2751,7 +2751,7 @@ package android.companion.virtual { method public void addActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener, @NonNull java.util.concurrent.Executor); method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close(); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback); - method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(int, int, int, @Nullable android.view.Surface, int, @Nullable android.os.Handler, @Nullable android.hardware.display.VirtualDisplay.Callback); + method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @NonNull java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index fdff27fb29f25..f1abb056da562 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -16,10 +16,11 @@ package android.companion.virtual; +import android.annotation.CallbackExecutor; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.Activity; @@ -31,6 +32,7 @@ import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.VirtualDisplayFlag; import android.hardware.display.VirtualDisplay; import android.hardware.display.VirtualDisplayConfig; import android.hardware.input.VirtualKeyboard; @@ -46,6 +48,7 @@ import android.os.ResultReceiver; import android.util.ArrayMap; import android.view.Surface; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -210,25 +213,22 @@ public final class VirtualDeviceManager { * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. + * @param executor The executor on which {@code callback} will be invoked. This is ignored + * if {@code callback} is {@code null}. * @param callback Callback to call when the state of the {@link VirtualDisplay} changes - * @param handler The handler on which the listener should be invoked, or null - * if the listener should be invoked on the calling thread's looper. * @return The newly created virtual display, or {@code null} if the application could * not create the virtual display. * * @see DisplayManager#createVirtualDisplay */ - // Suppress "ExecutorRegistration" because DisplayManager.createVirtualDisplay takes a - // handler - @SuppressLint("ExecutorRegistration") @Nullable public VirtualDisplay createVirtualDisplay( - int width, - int height, - int densityDpi, + @IntRange(from = 1) int width, + @IntRange(from = 1) int height, + @IntRange(from = 1) int densityDpi, @Nullable Surface surface, - int flags, - @Nullable Handler handler, + @VirtualDisplayFlag int flags, + @NonNull @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { // TODO(b/205343547): Handle display groups properly instead of creating a new display // group for every new virtual display created using this API. @@ -244,7 +244,7 @@ public final class VirtualDeviceManager { .setFlags(getVirtualDisplayFlags(flags)) .build(), callback, - handler); + Objects.requireNonNull(executor)); } /** diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 623f38e3f48bd..971b61bacd97e 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -22,6 +22,7 @@ import static android.view.Display.HdrCapabilities.HdrType; import android.Manifest; import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -38,6 +39,8 @@ import android.graphics.Point; import android.media.projection.MediaProjection; import android.os.Build; import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.Looper; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -48,6 +51,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; /** @@ -104,6 +108,25 @@ public final class DisplayManager { public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION"; + /** @hide **/ + @IntDef(prefix = "VIRTUAL_DISPLAY_FLAG_", flag = true, value = { + VIRTUAL_DISPLAY_FLAG_PUBLIC, + VIRTUAL_DISPLAY_FLAG_PRESENTATION, + VIRTUAL_DISPLAY_FLAG_SECURE, + VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, + VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, + VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD, + VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH, + VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT, + VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL, + VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS, + VIRTUAL_DISPLAY_FLAG_TRUSTED, + VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, + VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface VirtualDisplayFlag {} + /** * Virtual display flag: Create a public display. * @@ -820,7 +843,11 @@ public final class DisplayManager { * VirtualDisplay.Callback, Handler) */ public VirtualDisplay createVirtualDisplay(@NonNull String name, - int width, int height, int densityDpi, @Nullable Surface surface, int flags) { + @IntRange(from = 1) int width, + @IntRange(from = 1) int height, + @IntRange(from = 1) int densityDpi, + @Nullable Surface surface, + @VirtualDisplayFlag int flags) { return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null); } @@ -868,8 +895,13 @@ public final class DisplayManager { * a virtual display with the specified flags. */ public VirtualDisplay createVirtualDisplay(@NonNull String name, - int width, int height, int densityDpi, @Nullable Surface surface, int flags, - @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { + @IntRange(from = 1) int width, + @IntRange(from = 1) int height, + @IntRange(from = 1) int densityDpi, + @Nullable Surface surface, + @VirtualDisplayFlag int flags, + @Nullable VirtualDisplay.Callback callback, + @Nullable Handler handler) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); builder.setFlags(flags); @@ -882,9 +914,16 @@ public final class DisplayManager { // TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService) /** @hide */ - public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, - @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, - int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, + public VirtualDisplay createVirtualDisplay( + @Nullable MediaProjection projection, + @NonNull String name, + @IntRange(from = 1) int width, + @IntRange(from = 1) int height, + @IntRange(from = 1) int densityDpi, + @Nullable Surface surface, + @VirtualDisplayFlag int flags, + @Nullable VirtualDisplay.Callback callback, + @Nullable Handler handler, @Nullable String uniqueId) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); @@ -904,16 +943,24 @@ public final class DisplayManager { @NonNull VirtualDisplayConfig virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable Context windowContext) { + Executor executor = null; + // If callback is null, the executor will not be used. Avoid creating the handler and the + // handler executor. + if (callback != null) { + executor = new HandlerExecutor( + Handler.createAsync(handler != null ? handler.getLooper() : Looper.myLooper())); + } return mGlobal.createVirtualDisplay(mContext, projection, null /* virtualDevice */, - virtualDisplayConfig, callback, handler, windowContext); + virtualDisplayConfig, callback, executor, windowContext); } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig, - @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { + @Nullable VirtualDisplay.Callback callback, + @NonNull Executor executor) { return mGlobal.createVirtualDisplay(mContext, null /* projection */, virtualDevice, - virtualDisplayConfig, callback, handler, null); + virtualDisplayConfig, callback, executor, null); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 7e7a64803dd9b..889100d0f242a 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -56,6 +56,8 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executor; /** * Manager communication with the display manager service on behalf of @@ -585,8 +587,9 @@ public final class DisplayManagerGlobal { public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, IVirtualDevice virtualDevice, @NonNull VirtualDisplayConfig virtualDisplayConfig, - VirtualDisplay.Callback callback, Handler handler, @Nullable Context windowContext) { - VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); + VirtualDisplay.Callback callback, @Nullable Executor executor, + @Nullable Context windowContext) { + VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, executor); IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; int displayId; try { @@ -1048,61 +1051,36 @@ public final class DisplayManagerGlobal { } private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub { - private VirtualDisplayCallbackDelegate mDelegate; + @Nullable private final VirtualDisplay.Callback mCallback; + @Nullable private final Executor mExecutor; - public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) { - if (callback != null) { - mDelegate = new VirtualDisplayCallbackDelegate(callback, handler); - } + VirtualDisplayCallback(VirtualDisplay.Callback callback, Executor executor) { + mCallback = callback; + mExecutor = mCallback != null ? Objects.requireNonNull(executor) : null; } + // These methods are called from the binder thread, but the AIDL is oneway, so it should be + // safe to call the callback on arbitrary executors directly without risking blocking + // the system. + @Override // Binder call public void onPaused() { - if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED); + if (mCallback != null) { + mExecutor.execute(mCallback::onPaused); } } @Override // Binder call public void onResumed() { - if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED); + if (mCallback != null) { + mExecutor.execute(mCallback::onResumed); } } @Override // Binder call public void onStopped() { - if (mDelegate != null) { - mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED); - } - } - } - - private final static class VirtualDisplayCallbackDelegate extends Handler { - public static final int MSG_DISPLAY_PAUSED = 0; - public static final int MSG_DISPLAY_RESUMED = 1; - public static final int MSG_DISPLAY_STOPPED = 2; - - private final VirtualDisplay.Callback mCallback; - - public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback, - Handler handler) { - super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/); - mCallback = callback; - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_DISPLAY_PAUSED: - mCallback.onPaused(); - break; - case MSG_DISPLAY_RESUMED: - mCallback.onResumed(); - break; - case MSG_DISPLAY_STOPPED: - mCallback.onStopped(); - break; + if (mCallback != null) { + mExecutor.execute(mCallback::onStopped); } } } diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index 0e86f43207aae..e292394c36ff6 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.display.DisplayManager.VirtualDisplayFlag; import android.media.projection.MediaProjection; import android.os.Handler; import android.os.IBinder; @@ -70,6 +71,7 @@ public final class VirtualDisplayConfig implements Parcelable { * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}, * or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. */ + @VirtualDisplayFlag private int mFlags = 0; /** @@ -120,7 +122,7 @@ public final class VirtualDisplayConfig implements Parcelable { @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, - int flags, + @VirtualDisplayFlag int flags, @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, @@ -141,6 +143,8 @@ public final class VirtualDisplayConfig implements Parcelable { IntRange.class, null, mDensityDpi, "from", 1); this.mFlags = flags; + com.android.internal.util.AnnotationValidations.validate( + VirtualDisplayFlag.class, null, mFlags); this.mSurface = surface; this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; @@ -190,7 +194,7 @@ public final class VirtualDisplayConfig implements Parcelable { * or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. */ @DataClass.Generated.Member - public int getFlags() { + public @VirtualDisplayFlag int getFlags() { return mFlags; } @@ -291,6 +295,8 @@ public final class VirtualDisplayConfig implements Parcelable { IntRange.class, null, mDensityDpi, "from", 1); this.mFlags = flags; + com.android.internal.util.AnnotationValidations.validate( + VirtualDisplayFlag.class, null, mFlags); this.mSurface = surface; this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; @@ -324,7 +330,7 @@ public final class VirtualDisplayConfig implements Parcelable { private @IntRange(from = 1) int mWidth; private @IntRange(from = 1) int mHeight; private @IntRange(from = 1) int mDensityDpi; - private int mFlags; + private @VirtualDisplayFlag int mFlags; private @Nullable Surface mSurface; private @Nullable String mUniqueId; private int mDisplayIdToMirror; @@ -419,7 +425,7 @@ public final class VirtualDisplayConfig implements Parcelable { * or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. */ @DataClass.Generated.Member - public @NonNull Builder setFlags(int value) { + public @NonNull Builder setFlags(@VirtualDisplayFlag int value) { checkNotUsed(); mBuilderFieldsSet |= 0x10; mFlags = value; @@ -517,10 +523,10 @@ public final class VirtualDisplayConfig implements Parcelable { } @DataClass.Generated( - time = 1620657851981L, + time = 1643938791506L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") + inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") @Deprecated private void __metadata() {}