diff options
| author | 2023-01-19 17:39:21 +0000 | |
|---|---|---|
| committer | 2023-01-19 17:39:21 +0000 | |
| commit | 26006c72dda345d65f323a2fec8c65a41b7947a6 (patch) | |
| tree | 408dd979f73747067817f67ffe713fa8f40b337a | |
| parent | 61fc8edea5df13e25c7436634baf1a7b282590d5 (diff) | |
| parent | a5e45d312420345a908e895e121faa08a908e072 (diff) | |
Merge "Make ScreenshotRequest handle hardware bitmap conversion" into tm-qpr-dev am: a5e45d3124
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20894854
Change-Id: I59821a3f0851624e07b169d83bc190bc9345556b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
21 files changed, 794 insertions, 450 deletions
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java index 79c519645a24..3a393b689717 100644 --- a/core/java/com/android/internal/util/ScreenshotHelper.java +++ b/core/java/com/android/internal/util/ScreenshotHelper.java @@ -1,7 +1,7 @@ package com.android.internal.util; import static android.content.Intent.ACTION_USER_SWITCHED; -import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE; +import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; import android.annotation.NonNull; import android.annotation.Nullable; @@ -11,29 +11,18 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.graphics.Bitmap; -import android.graphics.ColorSpace; -import android.graphics.Insets; -import android.graphics.ParcelableColorSpace; -import android.graphics.Rect; -import android.hardware.HardwareBuffer; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; -import android.os.Parcel; -import android.os.Parcelable; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.view.WindowManager.ScreenshotSource; -import android.view.WindowManager.ScreenshotType; import com.android.internal.annotations.VisibleForTesting; -import java.util.Objects; import java.util.function.Consumer; public class ScreenshotHelper { @@ -41,212 +30,6 @@ public class ScreenshotHelper { public static final int SCREENSHOT_MSG_URI = 1; public static final int SCREENSHOT_MSG_PROCESS_COMPLETE = 2; - /** - * Describes a screenshot request. - */ - public static class ScreenshotRequest implements Parcelable { - @ScreenshotType - private final int mType; - - @ScreenshotSource - private final int mSource; - - private final Bundle mBitmapBundle; - private final Rect mBoundsInScreen; - private final Insets mInsets; - private final int mTaskId; - private final int mUserId; - private final ComponentName mTopComponent; - - - public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source) { - this(type, source, /* topComponent */ null); - } - - public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source, - ComponentName topComponent) { - this(type, - source, - /* bitmapBundle*/ null, - /* boundsInScreen */ null, - /* insets */ null, - /* taskId */ -1, - /* userId */ -1, - topComponent); - } - - public ScreenshotRequest(@ScreenshotType int type, @ScreenshotSource int source, - Bundle bitmapBundle, Rect boundsInScreen, Insets insets, int taskId, int userId, - ComponentName topComponent) { - mType = type; - mSource = source; - mBitmapBundle = bitmapBundle; - mBoundsInScreen = boundsInScreen; - mInsets = insets; - mTaskId = taskId; - mUserId = userId; - mTopComponent = topComponent; - } - - ScreenshotRequest(Parcel in) { - mType = in.readInt(); - mSource = in.readInt(); - if (in.readInt() == 1) { - mBitmapBundle = in.readBundle(getClass().getClassLoader()); - mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader(), Rect.class); - mInsets = in.readParcelable(Insets.class.getClassLoader(), Insets.class); - mTaskId = in.readInt(); - mUserId = in.readInt(); - mTopComponent = in.readParcelable(ComponentName.class.getClassLoader(), - ComponentName.class); - } else { - mBitmapBundle = null; - mBoundsInScreen = null; - mInsets = null; - mTaskId = -1; - mUserId = -1; - mTopComponent = null; - } - } - - @ScreenshotType - public int getType() { - return mType; - } - - @ScreenshotSource - public int getSource() { - return mSource; - } - - public Bundle getBitmapBundle() { - return mBitmapBundle; - } - - public Rect getBoundsInScreen() { - return mBoundsInScreen; - } - - public Insets getInsets() { - return mInsets; - } - - public int getTaskId() { - return mTaskId; - } - - public int getUserId() { - return mUserId; - } - - public ComponentName getTopComponent() { - return mTopComponent; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mType); - dest.writeInt(mSource); - if (mBitmapBundle == null) { - dest.writeInt(0); - } else { - dest.writeInt(1); - dest.writeBundle(mBitmapBundle); - dest.writeParcelable(mBoundsInScreen, 0); - dest.writeParcelable(mInsets, 0); - dest.writeInt(mTaskId); - dest.writeInt(mUserId); - dest.writeParcelable(mTopComponent, 0); - } - } - - @NonNull - public static final Parcelable.Creator<ScreenshotRequest> CREATOR = - new Parcelable.Creator<ScreenshotRequest>() { - - @Override - public ScreenshotRequest createFromParcel(Parcel source) { - return new ScreenshotRequest(source); - } - - @Override - public ScreenshotRequest[] newArray(int size) { - return new ScreenshotRequest[size]; - } - }; - } - - /** - * Bundler used to convert between a hardware bitmap and a bundle without copying the internal - * content. This is expected to be used together with {@link #provideScreenshot} to handle a - * hardware bitmap as a screenshot. - */ - public static final class HardwareBitmapBundler { - private static final String KEY_BUFFER = "bitmap_util_buffer"; - private static final String KEY_COLOR_SPACE = "bitmap_util_color_space"; - - private HardwareBitmapBundler() { - } - - /** - * Creates a Bundle that represents the given Bitmap. - * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid - * copies when passing across processes, only pass to processes you trust. - * - * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the - * returned Bundle should be treated as a standalone object. - * - * @param bitmap to convert to bundle - * @return a Bundle representing the bitmap, should only be parsed by - * {@link #bundleToHardwareBitmap(Bundle)} - */ - public static Bundle hardwareBitmapToBundle(Bitmap bitmap) { - if (bitmap.getConfig() != Bitmap.Config.HARDWARE) { - throw new IllegalArgumentException( - "Passed bitmap must have hardware config, found: " + bitmap.getConfig()); - } - - // Bitmap assumes SRGB for null color space - ParcelableColorSpace colorSpace = - bitmap.getColorSpace() == null - ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB)) - : new ParcelableColorSpace(bitmap.getColorSpace()); - - Bundle bundle = new Bundle(); - bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer()); - bundle.putParcelable(KEY_COLOR_SPACE, colorSpace); - - return bundle; - } - - /** - * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .} - * - * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing - * this Bitmap on to any other source. - * - * @param bundle containing the bitmap - * @return a hardware Bitmap - */ - public static Bitmap bundleToHardwareBitmap(Bundle bundle) { - if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) { - throw new IllegalArgumentException("Bundle does not contain a hardware bitmap"); - } - - HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, HardwareBuffer.class); - ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE, - ParcelableColorSpace.class); - - return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), - colorSpace.getColorSpace()); - } - } - private static final String TAG = "ScreenshotHelper"; // Time until we give up on the screenshot & show an error instead. @@ -277,68 +60,53 @@ public class ScreenshotHelper { /** * Request a screenshot be taken. * <p> - * Added to support reducing unit test duration; the method variant without a timeout argument - * is recommended for general use. + * Convenience method for taking a full screenshot with provided source. * - * @param type The type of screenshot, defined by {@link ScreenshotType} - * @param source The source of the screenshot request, defined by {@link ScreenshotSource} - * @param handler used to process messages received from the screenshot service + * @param source source of the screenshot request, defined by {@link + * ScreenshotSource} + * @param handler used to process messages received from the screenshot service * @param completionConsumer receives the URI of the captured screenshot, once saved or - * null if no screenshot was saved + * null if no screenshot was saved */ - public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source, - @NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) { - ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source); - takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS, - completionConsumer); + public void takeScreenshot(@ScreenshotSource int source, @NonNull Handler handler, + @Nullable Consumer<Uri> completionConsumer) { + ScreenshotRequest request = + new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, source).build(); + takeScreenshot(request, handler, completionConsumer); } /** * Request a screenshot be taken. * <p> - * Added to support reducing unit test duration; the method variant without a timeout argument - * is recommended for general use. * - * @param type The type of screenshot, defined by {@link ScreenshotType} - * @param source The source of the screenshot request, defined by {@link ScreenshotSource} - * @param handler used to process messages received from the screenshot service - * @param timeoutMs time limit for processing, intended only for testing + * @param request description of the screenshot request, either for taking a + * screenshot or + * providing a bitmap + * @param handler used to process messages received from the screenshot service * @param completionConsumer receives the URI of the captured screenshot, once saved or - * null if no screenshot was saved + * null if no screenshot was saved */ - @VisibleForTesting - public void takeScreenshot(@ScreenshotType int type, @ScreenshotSource int source, - @NonNull Handler handler, long timeoutMs, @Nullable Consumer<Uri> completionConsumer) { - ScreenshotRequest screenshotRequest = new ScreenshotRequest(type, source); - takeScreenshot(handler, screenshotRequest, timeoutMs, completionConsumer); + public void takeScreenshot(ScreenshotRequest request, @NonNull Handler handler, + @Nullable Consumer<Uri> completionConsumer) { + takeScreenshotInternal(request, handler, completionConsumer, SCREENSHOT_TIMEOUT_MS); } /** - * Request that provided image be handled as if it was a screenshot. + * Request a screenshot be taken. + * <p> + * Added to support reducing unit test duration; the method variant without a timeout argument + * is recommended for general use. * - * @param screenshotBundle Bundle containing the buffer and color space of the screenshot. - * @param boundsInScreen The bounds in screen coordinates that the bitmap originated from. - * @param insets The insets that the image was shown with, inside the screen bounds. - * @param taskId The taskId of the task that the screen shot was taken of. - * @param userId The userId of user running the task provided in taskId. - * @param topComponent The component name of the top component running in the task. - * @param source The source of the screenshot request, defined by {@link ScreenshotSource} - * @param handler A handler used in case the screenshot times out + * @param request description of the screenshot request, either for taking a + * screenshot or providing a bitmap + * @param handler used to process messages received from the screenshot service + * @param timeoutMs time limit for processing, intended only for testing * @param completionConsumer receives the URI of the captured screenshot, once saved or - * null if no screenshot was saved + * null if no screenshot was saved */ - public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen, - @NonNull Insets insets, int taskId, int userId, ComponentName topComponent, - @ScreenshotSource int source, @NonNull Handler handler, - @Nullable Consumer<Uri> completionConsumer) { - ScreenshotRequest screenshotRequest = new ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, - source, screenshotBundle, boundsInScreen, insets, taskId, userId, topComponent); - takeScreenshot(handler, screenshotRequest, SCREENSHOT_TIMEOUT_MS, completionConsumer); - } - - private void takeScreenshot(@NonNull Handler handler, - ScreenshotRequest screenshotRequest, long timeoutMs, - @Nullable Consumer<Uri> completionConsumer) { + @VisibleForTesting + public void takeScreenshotInternal(ScreenshotRequest request, @NonNull Handler handler, + @Nullable Consumer<Uri> completionConsumer, long timeoutMs) { synchronized (mScreenshotLock) { final Runnable mScreenshotTimeout = () -> { @@ -354,7 +122,7 @@ public class ScreenshotHelper { } }; - Message msg = Message.obtain(null, 0, screenshotRequest); + Message msg = Message.obtain(null, 0, request); Handler h = new Handler(handler.getLooper()) { @Override @@ -471,5 +239,4 @@ public class ScreenshotHelper { Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT); } - } diff --git a/core/java/com/android/internal/util/ScreenshotRequest.aidl b/core/java/com/android/internal/util/ScreenshotRequest.aidl new file mode 100644 index 000000000000..b08905dd0c9a --- /dev/null +++ b/core/java/com/android/internal/util/ScreenshotRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 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 com.android.internal.util; + +parcelable ScreenshotRequest;
\ No newline at end of file diff --git a/core/java/com/android/internal/util/ScreenshotRequest.java b/core/java/com/android/internal/util/ScreenshotRequest.java new file mode 100644 index 000000000000..1902f80bd384 --- /dev/null +++ b/core/java/com/android/internal/util/ScreenshotRequest.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2023 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 com.android.internal.util; + +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.os.UserHandle.USER_NULL; +import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; +import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.graphics.Bitmap; +import android.graphics.ColorSpace; +import android.graphics.Insets; +import android.graphics.ParcelableColorSpace; +import android.graphics.Rect; +import android.hardware.HardwareBuffer; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; +import android.view.WindowManager; + +import java.util.Objects; + +/** + * Describes a screenshot request. + */ +public class ScreenshotRequest implements Parcelable { + private static final String TAG = "ScreenshotRequest"; + + @WindowManager.ScreenshotType + private final int mType; + @WindowManager.ScreenshotSource + private final int mSource; + private final ComponentName mTopComponent; + private final int mTaskId; + private final int mUserId; + private final Bitmap mBitmap; + private final Rect mBoundsInScreen; + private final Insets mInsets; + + private ScreenshotRequest( + @WindowManager.ScreenshotType int type, @WindowManager.ScreenshotSource int source, + ComponentName topComponent, int taskId, int userId, + Bitmap bitmap, Rect boundsInScreen, Insets insets) { + mType = type; + mSource = source; + mTopComponent = topComponent; + mTaskId = taskId; + mUserId = userId; + mBitmap = bitmap; + mBoundsInScreen = boundsInScreen; + mInsets = insets; + } + + ScreenshotRequest(Parcel in) { + mType = in.readInt(); + mSource = in.readInt(); + mTopComponent = in.readTypedObject(ComponentName.CREATOR); + mTaskId = in.readInt(); + mUserId = in.readInt(); + mBitmap = HardwareBitmapBundler.bundleToHardwareBitmap(in.readTypedObject(Bundle.CREATOR)); + mBoundsInScreen = in.readTypedObject(Rect.CREATOR); + mInsets = in.readTypedObject(Insets.CREATOR); + } + + @WindowManager.ScreenshotType + public int getType() { + return mType; + } + + @WindowManager.ScreenshotSource + public int getSource() { + return mSource; + } + + public Bitmap getBitmap() { + return mBitmap; + } + + public Rect getBoundsInScreen() { + return mBoundsInScreen; + } + + public Insets getInsets() { + return mInsets; + } + + public int getTaskId() { + return mTaskId; + } + + public int getUserId() { + return mUserId; + } + + public ComponentName getTopComponent() { + return mTopComponent; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mType); + dest.writeInt(mSource); + dest.writeTypedObject(mTopComponent, 0); + dest.writeInt(mTaskId); + dest.writeInt(mUserId); + dest.writeTypedObject(HardwareBitmapBundler.hardwareBitmapToBundle(mBitmap), 0); + dest.writeTypedObject(mBoundsInScreen, 0); + dest.writeTypedObject(mInsets, 0); + } + + @NonNull + public static final Parcelable.Creator<ScreenshotRequest> CREATOR = + new Parcelable.Creator<ScreenshotRequest>() { + + @Override + public ScreenshotRequest createFromParcel(Parcel source) { + return new ScreenshotRequest(source); + } + + @Override + public ScreenshotRequest[] newArray(int size) { + return new ScreenshotRequest[size]; + } + }; + + /** + * Builder class for {@link ScreenshotRequest} objects. + */ + public static class Builder { + @WindowManager.ScreenshotType + private final int mType; + + @WindowManager.ScreenshotSource + private final int mSource; + + private Bitmap mBitmap; + private Rect mBoundsInScreen; + private Insets mInsets = Insets.NONE; + private int mTaskId = INVALID_TASK_ID; + private int mUserId = USER_NULL; + private ComponentName mTopComponent; + + /** + * Begin building a ScreenshotRequest. + * + * @param type The type of the screenshot request, defined by {@link + * WindowManager.ScreenshotType} + * @param source The source of the screenshot request, defined by {@link + * WindowManager.ScreenshotSource} + */ + public Builder( + @WindowManager.ScreenshotType int type, + @WindowManager.ScreenshotSource int source) { + mType = type; + mSource = source; + } + + /** + * Construct a new {@link ScreenshotRequest} with the set parameters. + */ + public ScreenshotRequest build() { + if (mType == TAKE_SCREENSHOT_FULLSCREEN && mBitmap != null) { + Log.w(TAG, "Bitmap provided, but request is fullscreen. Bitmap will be ignored."); + } + if (mType == TAKE_SCREENSHOT_PROVIDED_IMAGE && mBitmap == null) { + throw new IllegalStateException( + "Request is PROVIDED_IMAGE, but no bitmap is provided!"); + } + + return new ScreenshotRequest(mType, mSource, mTopComponent, mTaskId, mUserId, mBitmap, + mBoundsInScreen, mInsets); + } + + /** + * Set the top component associated with this request. + * + * @param topComponent The component name of the top component running in the task. + */ + public Builder setTopComponent(ComponentName topComponent) { + mTopComponent = topComponent; + return this; + } + + /** + * Set the task id associated with this request. + * + * @param taskId The taskId of the task that the screenshot was taken of. + */ + public Builder setTaskId(int taskId) { + mTaskId = taskId; + return this; + } + + /** + * Set the user id associated with this request. + * + * @param userId The userId of user running the task provided in taskId. + */ + public Builder setUserId(int userId) { + mUserId = userId; + return this; + } + + /** + * Set the bitmap associated with this request. + * + * @param bitmap The provided screenshot. + */ + public Builder setBitmap(Bitmap bitmap) { + mBitmap = bitmap; + return this; + } + + /** + * Set the bounds for the provided bitmap. + * + * @param bounds The bounds in screen coordinates that the bitmap originated from. + */ + public Builder setBoundsOnScreen(Rect bounds) { + mBoundsInScreen = bounds; + return this; + } + + /** + * Set the insets for the provided bitmap. + * + * @param insets The insets that the image was shown with, inside the screen bounds. + */ + public Builder setInsets(@NonNull Insets insets) { + mInsets = insets; + return this; + } + } + + /** + * Bundler used to convert between a hardware bitmap and a bundle without copying the internal + * content. This is used together with a fully-defined ScreenshotRequest to handle a hardware + * bitmap as a screenshot. + */ + private static final class HardwareBitmapBundler { + private static final String KEY_BUFFER = "bitmap_util_buffer"; + private static final String KEY_COLOR_SPACE = "bitmap_util_color_space"; + + private HardwareBitmapBundler() { + } + + /** + * Creates a Bundle that represents the given Bitmap. + * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will + * avoid + * copies when passing across processes, only pass to processes you trust. + * + * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, + * the + * returned Bundle should be treated as a standalone object. + * + * @param bitmap to convert to bundle + * @return a Bundle representing the bitmap, should only be parsed by + * {@link #bundleToHardwareBitmap(Bundle)} + */ + private static Bundle hardwareBitmapToBundle(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + if (bitmap.getConfig() != Bitmap.Config.HARDWARE) { + throw new IllegalArgumentException( + "Passed bitmap must have hardware config, found: " + + bitmap.getConfig()); + } + + // Bitmap assumes SRGB for null color space + ParcelableColorSpace colorSpace = + bitmap.getColorSpace() == null + ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB)) + : new ParcelableColorSpace(bitmap.getColorSpace()); + + Bundle bundle = new Bundle(); + bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer()); + bundle.putParcelable(KEY_COLOR_SPACE, colorSpace); + + return bundle; + } + + /** + * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)}. + * + * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful + * passing + * this Bitmap on to any other source. + * + * @param bundle containing the bitmap + * @return a hardware Bitmap + */ + private static Bitmap bundleToHardwareBitmap(Bundle bundle) { + if (bundle == null) { + return null; + } + if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) { + throw new IllegalArgumentException("Bundle does not contain a hardware bitmap"); + } + + HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, HardwareBuffer.class); + ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE, + ParcelableColorSpace.class); + + return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), + colorSpace.getColorSpace()); + } + } +} diff --git a/core/tests/screenshothelpertests/Android.bp b/core/tests/screenshothelpertests/Android.bp index 37af99c58d42..3c71e6e4247b 100644 --- a/core/tests/screenshothelpertests/Android.bp +++ b/core/tests/screenshothelpertests/Android.bp @@ -13,7 +13,7 @@ android_test { srcs: [ "src/**/*.java", ], - + static_libs: [ "frameworks-base-testutils", "androidx.test.runner", @@ -21,6 +21,7 @@ android_test { "androidx.test.ext.junit", "mockito-target-minus-junit4", "platform-test-annotations", + "testng", ], libs: [ diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java index 2719431a536e..5c9894ebd590 100644 --- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java +++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java @@ -17,6 +17,7 @@ package com.android.internal.util; import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; +import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.fail; @@ -31,9 +32,11 @@ import static org.mockito.Mockito.mock; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.ColorSpace; import android.graphics.Insets; import android.graphics.Rect; -import android.os.Bundle; +import android.hardware.HardwareBuffer; import android.os.Handler; import android.os.Looper; import android.view.WindowManager; @@ -79,30 +82,48 @@ public final class ScreenshotHelperTest { @Test public void testFullscreenScreenshot() { - mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, + mScreenshotHelper.takeScreenshot( WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null); } @Test + public void testFullscreenScreenshotRequest() { + ScreenshotRequest request = new ScreenshotRequest.Builder( + TAKE_SCREENSHOT_FULLSCREEN, WindowManager.ScreenshotSource.SCREENSHOT_OTHER) + .build(); + mScreenshotHelper.takeScreenshot(request, mHandler, null); + } + + @Test public void testProvidedImageScreenshot() { - mScreenshotHelper.provideScreenshot( - new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""), - WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null); + HardwareBuffer buffer = HardwareBuffer.create( + 10, 10, HardwareBuffer.RGBA_8888, 1, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); + Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB)); + ScreenshotRequest request = new ScreenshotRequest.Builder( + TAKE_SCREENSHOT_PROVIDED_IMAGE, WindowManager.ScreenshotSource.SCREENSHOT_OTHER) + .setTopComponent(new ComponentName("", "")) + .setTaskId(1) + .setUserId(1) + .setBitmap(bitmap) + .setBoundsOnScreen(new Rect()) + .setInsets(Insets.NONE) + .build(); + mScreenshotHelper.takeScreenshot(request, mHandler, null); } @Test public void testScreenshotTimesOut() { long timeoutMs = 10; + ScreenshotRequest request = new ScreenshotRequest.Builder( + TAKE_SCREENSHOT_FULLSCREEN, WindowManager.ScreenshotSource.SCREENSHOT_OTHER) + .build(); CountDownLatch lock = new CountDownLatch(1); - mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, - WindowManager.ScreenshotSource.SCREENSHOT_OTHER, - mHandler, - timeoutMs, + mScreenshotHelper.takeScreenshotInternal(request, mHandler, uri -> { assertNull(uri); lock.countDown(); - }); + }, timeoutMs); try { // Add tolerance for delay to prevent flakes. diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java new file mode 100644 index 000000000000..30540a5f013b --- /dev/null +++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotRequestTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2023 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 com.android.internal.util; + +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.os.UserHandle.USER_NULL; +import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER; +import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; +import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; + +import static org.testng.Assert.assertThrows; + +import android.content.ComponentName; +import android.graphics.Bitmap; +import android.graphics.ColorSpace; +import android.graphics.Insets; +import android.graphics.Rect; +import android.hardware.HardwareBuffer; +import android.os.Parcel; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public final class ScreenshotRequestTest { + private final ComponentName mComponentName = + new ComponentName("android.test", "android.test.Component"); + + @Test + public void testSimpleScreenshot() { + ScreenshotRequest in = + new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build(); + + Parcel parcel = Parcel.obtain(); + in.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel); + + assertEquals(TAKE_SCREENSHOT_FULLSCREEN, out.getType()); + assertEquals(SCREENSHOT_OTHER, out.getSource()); + assertNull("Top component was expected to be null", out.getTopComponent()); + assertEquals(INVALID_TASK_ID, out.getTaskId()); + assertEquals(USER_NULL, out.getUserId()); + assertNull("Bitmap was expected to be null", out.getBitmap()); + assertNull("Bounds were expected to be null", out.getBoundsInScreen()); + assertEquals(Insets.NONE, out.getInsets()); + } + + @Test + public void testProvidedScreenshot() { + Bitmap bitmap = makeHardwareBitmap(50, 50); + ScreenshotRequest in = + new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(mComponentName) + .setTaskId(2) + .setUserId(3) + .setBitmap(bitmap) + .setBoundsOnScreen(new Rect(10, 10, 60, 60)) + .setInsets(Insets.of(2, 3, 4, 5)) + .build(); + + Parcel parcel = Parcel.obtain(); + in.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel); + + assertEquals(TAKE_SCREENSHOT_PROVIDED_IMAGE, out.getType()); + assertEquals(SCREENSHOT_OTHER, out.getSource()); + assertEquals(mComponentName, out.getTopComponent()); + assertEquals(2, out.getTaskId()); + assertEquals(3, out.getUserId()); + assertTrue("Bitmaps should be equal", out.getBitmap().sameAs(bitmap)); + assertEquals(new Rect(10, 10, 60, 60), out.getBoundsInScreen()); + assertEquals(Insets.of(2, 3, 4, 5), out.getInsets()); + } + + @Test + public void testProvidedScreenshot_nullBitmap() { + ScreenshotRequest.Builder inBuilder = + new ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(mComponentName) + .setTaskId(2) + .setUserId(3) + .setBoundsOnScreen(new Rect(10, 10, 60, 60)) + .setInsets(Insets.of(2, 3, 4, 5)); + + assertThrows(IllegalStateException.class, inBuilder::build); + } + + @Test + public void testFullScreenshot_withBitmap() { + // A bitmap added to a FULLSCREEN request will be ignored, but it's technically valid + Bitmap bitmap = makeHardwareBitmap(50, 50); + ScreenshotRequest in = + new ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER) + .setBitmap(bitmap) + .build(); + + Parcel parcel = Parcel.obtain(); + in.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + ScreenshotRequest out = ScreenshotRequest.CREATOR.createFromParcel(parcel); + + assertEquals(TAKE_SCREENSHOT_FULLSCREEN, out.getType()); + assertEquals(SCREENSHOT_OTHER, out.getSource()); + assertNull(out.getTopComponent()); + assertEquals(INVALID_TASK_ID, out.getTaskId()); + assertEquals(USER_NULL, out.getUserId()); + assertTrue("Bitmaps should be equal", out.getBitmap().sameAs(bitmap)); + assertNull("Bounds expected to be null", out.getBoundsInScreen()); + assertEquals(Insets.NONE, out.getInsets()); + } + + private Bitmap makeHardwareBitmap(int width, int height) { + HardwareBuffer buffer = HardwareBuffer.create( + width, height, HardwareBuffer.RGBA_8888, 1, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); + return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB)); + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 1c532fe7a529..b8bddd149d9a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -22,6 +22,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; import android.view.MotionEvent; +import com.android.internal.util.ScreenshotRequest; import com.android.systemui.shared.recents.model.Task; @@ -87,12 +88,6 @@ interface ISystemUiProxy { void notifyPrioritizedRotation(int rotation) = 25; /** - * Handle the provided image as if it was a screenshot. - */ - void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen, - in Insets visibleInsets, in Task.TaskKey task) = 28; - - /** * Notifies to expand notification panel. */ void expandNotificationPanel() = 29; @@ -125,5 +120,10 @@ interface ISystemUiProxy { */ void toggleNotificationPanel() = 50; - // Next id = 51 + /** + * Handle the screenshot request. + */ + void takeScreenshot(in ScreenshotRequest request) = 51; + + // Next id = 52 } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index dab73e9bf289..e16fa9dbf33a 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -42,7 +42,6 @@ import android.view.IWindowManager; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; @@ -343,6 +342,7 @@ public class SystemActions implements CoreStartable { /** * Register a system action. + * * @param actionId the action ID to register. */ public void register(int actionId) { @@ -440,6 +440,7 @@ public class SystemActions implements CoreStartable { /** * Unregister a system action. + * * @param actionId the action ID to unregister. */ public void unregister(int actionId) { @@ -475,7 +476,8 @@ public class SystemActions implements CoreStartable { } private void handleNotifications() { - mCentralSurfacesOptionalLazy.get().ifPresent(CentralSurfaces::animateExpandNotificationsPanel); + mCentralSurfacesOptionalLazy.get().ifPresent( + CentralSurfaces::animateExpandNotificationsPanel); } private void handleQuickSettings() { @@ -507,7 +509,7 @@ public class SystemActions implements CoreStartable { private void handleTakeScreenshot() { ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext); - screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + screenshotHelper.takeScreenshot( SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null); } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index db2cd91374e5..1e61f648b82d 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -21,7 +21,6 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS; -import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; @@ -959,8 +958,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mHandler.postDelayed(new Runnable() { @Override public void run() { - mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, - SCREENSHOT_GLOBAL_ACTIONS, mHandler, null); + mScreenshotHelper.takeScreenshot(SCREENSHOT_GLOBAL_ACTIONS, mHandler, null); mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU); mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 4d005bebd99e..543f1bdc70d0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -21,7 +21,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; -import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; @@ -44,8 +43,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.graphics.Insets; -import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; import android.os.Binder; @@ -77,6 +74,7 @@ import com.android.internal.app.IVoiceInteractionSessionListener; import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.ScreenshotHelper; +import com.android.internal.util.ScreenshotRequest; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -94,7 +92,6 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; -import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -322,18 +319,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } @Override - public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen, - Insets visibleInsets, Task.TaskKey task) { - mScreenshotHelper.provideScreenshot( - screenImageBundle, - locationInScreen, - visibleInsets, - task.id, - task.userId, - task.sourceComponent, - SCREENSHOT_OVERVIEW, - mHandler, - null); + public void takeScreenshot(ScreenshotRequest request) { + mScreenshotHelper.takeScreenshot(request, mHandler, null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt index 95cc0dcadfb4..f011aab9da0f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt @@ -19,27 +19,26 @@ package com.android.systemui.screenshot import android.graphics.Insets import android.util.Log import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE -import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler -import com.android.internal.util.ScreenshotHelper.ScreenshotRequest +import com.android.internal.util.ScreenshotRequest import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY -import java.util.function.Consumer -import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import java.util.function.Consumer +import javax.inject.Inject /** * Processes a screenshot request sent from {@link ScreenshotHelper}. */ @SysUISingleton class RequestProcessor @Inject constructor( - private val capture: ImageCapture, - private val policy: ScreenshotPolicy, - private val flags: FeatureFlags, - /** For the Java Async version, to invoke the callback. */ - @Application private val mainScope: CoroutineScope + private val capture: ImageCapture, + private val policy: ScreenshotPolicy, + private val flags: FeatureFlags, + /** For the Java Async version, to invoke the callback. */ + @Application private val mainScope: CoroutineScope ) { /** * Inspects the incoming request, returning a potentially modified request depending on policy. @@ -58,7 +57,7 @@ class RequestProcessor @Inject constructor( // regardless of the managed profile status. if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE && - flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY) + flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY) ) { val info = policy.findPrimaryContent(policy.getDefaultDisplayId()) @@ -66,17 +65,21 @@ class RequestProcessor @Inject constructor( result = if (policy.isManagedProfile(info.user.identifier)) { val image = capture.captureTask(info.taskId) - ?: error("Task snapshot returned a null Bitmap!") + ?: error("Task snapshot returned a null Bitmap!") // Provide the task snapshot as the screenshot - ScreenshotRequest( - TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source, - HardwareBitmapBundler.hardwareBitmapToBundle(image), - info.bounds, Insets.NONE, info.taskId, info.user.identifier, info.component - ) + ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source) + .setTopComponent(info.component) + .setTaskId(info.taskId) + .setUserId(info.user.identifier) + .setBitmap(image) + .setBoundsOnScreen(info.bounds) + .setInsets(Insets.NONE) + .build() } else { // Create a new request of the same type which includes the top component - ScreenshotRequest(request.type, request.source, info.component) + ScreenshotRequest.Builder(request.type, request.source) + .setTopComponent(info.component).build() } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 4f94ed18e1ef..6d87922f49eb 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -416,10 +416,11 @@ public class ScreenshotController { } boolean showFlash = false; - if (!aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { + if (screenshotScreenBounds == null + || !aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) { showFlash = true; visibleInsets = Insets.NONE; - screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight()); + screenshotScreenBounds = new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()); } mCurrentRequestCallback = requestCallback; saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index 35e9f3e56723..7b271a886d68 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -54,7 +54,7 @@ import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; -import com.android.internal.util.ScreenshotHelper; +import com.android.internal.util.ScreenshotRequest; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.flags.FeatureFlags; @@ -186,8 +186,7 @@ public class TakeScreenshotService extends Service { final Consumer<Uri> onSaved = (uri) -> reportUri(replyTo, uri); RequestCallback callback = new RequestCallbackImpl(replyTo); - ScreenshotHelper.ScreenshotRequest request = - (ScreenshotHelper.ScreenshotRequest) msg.obj; + ScreenshotRequest request = (ScreenshotRequest) msg.obj; handleRequest(request, onSaved, callback); return true; @@ -195,7 +194,7 @@ public class TakeScreenshotService extends Service { @MainThread @VisibleForTesting - void handleRequest(ScreenshotHelper.ScreenshotRequest request, Consumer<Uri> onSaved, + void handleRequest(ScreenshotRequest request, Consumer<Uri> onSaved, RequestCallback callback) { // If the storage for this user is locked, we have no place to store // the screenshot, so skip taking it instead of showing a misleading @@ -226,7 +225,7 @@ public class TakeScreenshotService extends Service { (r) -> dispatchToController(r, onSaved, callback)); } - private void dispatchToController(ScreenshotHelper.ScreenshotRequest request, + private void dispatchToController(ScreenshotRequest request, Consumer<Uri> uriConsumer, RequestCallback callback) { ComponentName topComponent = request.getTopComponent(); @@ -244,8 +243,7 @@ public class TakeScreenshotService extends Service { if (DEBUG_SERVICE) { Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE"); } - Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap( - request.getBitmapBundle()); + Bitmap screenshot = request.getBitmap(); Rect screenBounds = request.getBoundsInScreen(); Insets insets = request.getInsets(); int taskId = request.getTaskId(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt index 46a502acba16..ed3f1a059e61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt @@ -22,15 +22,12 @@ import android.graphics.ColorSpace import android.graphics.Insets import android.graphics.Rect import android.hardware.HardwareBuffer -import android.os.Bundle import android.os.UserHandle import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE -import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler -import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap -import com.android.internal.util.ScreenshotHelper.ScreenshotRequest +import com.android.internal.util.ScreenshotRequest import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo @@ -49,7 +46,6 @@ class RequestProcessorTest { private val bounds = Rect(25, 25, 75, 75) private val scope = CoroutineScope(Dispatchers.Unconfined) - private val dispatcher = Dispatchers.Unconfined private val policy = FakeScreenshotPolicy() private val flags = FakeFeatureFlags() @@ -58,7 +54,8 @@ class RequestProcessorTest { fun testProcessAsync() { flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false) - val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build() val processor = RequestProcessor(imageCapture, policy, flags, scope) var result: ScreenshotRequest? = null @@ -80,7 +77,8 @@ class RequestProcessorTest { fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking { flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false) - val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build() val processor = RequestProcessor(imageCapture, policy, flags, scope) val processedRequest = processor.process(request) @@ -97,9 +95,11 @@ class RequestProcessorTest { policy.setManagedProfile(USER_ID, false) policy.setDisplayContentInfo( policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID) + ) - val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_OTHER).build() val processor = RequestProcessor(imageCapture, policy, flags, scope) val processedRequest = processor.process(request) @@ -120,17 +120,20 @@ class RequestProcessorTest { // Indicate that the primary content belongs to a manged profile policy.setManagedProfile(USER_ID, true) - policy.setDisplayContentInfo(policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) + policy.setDisplayContentInfo( + policy.getDefaultDisplayId(), + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID) + ) - val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD).build() val processor = RequestProcessor(imageCapture, policy, flags, scope) val processedRequest = processor.process(request) // Expect a task snapshot is taken, overriding the full screen mode assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE) - assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue() + assertThat(bitmap.equalsHardwareBitmap(processedRequest.bitmap)).isTrue() assertThat(processedRequest.boundsInScreen).isEqualTo(bounds) assertThat(processedRequest.insets).isEqualTo(Insets.NONE) assertThat(processedRequest.taskId).isEqualTo(TASK_ID) @@ -147,10 +150,16 @@ class RequestProcessorTest { val processor = RequestProcessor(imageCapture, policy, flags, scope) val bitmap = makeHardwareBitmap(100, 100) - val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap) - val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER, - bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(component) + .setTaskId(TASK_ID) + .setUserId(USER_ID) + .setBitmap(bitmap) + .setBoundsOnScreen(bounds) + .setInsets(Insets.NONE) + .build() val processedRequest = processor.process(request) @@ -168,10 +177,16 @@ class RequestProcessorTest { policy.setManagedProfile(USER_ID, false) val bitmap = makeHardwareBitmap(100, 100) - val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap) - val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER, - bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(component) + .setTaskId(TASK_ID) + .setUserId(USER_ID) + .setBitmap(bitmap) + .setBoundsOnScreen(bounds) + .setInsets(Insets.NONE) + .build() val processedRequest = processor.process(request) @@ -190,10 +205,16 @@ class RequestProcessorTest { policy.setManagedProfile(USER_ID, true) val bitmap = makeHardwareBitmap(100, 100) - val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap) - val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER, - bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, component) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(component) + .setTaskId(TASK_ID) + .setUserId(USER_ID) + .setBitmap(bitmap) + .setBoundsOnScreen(bounds) + .setInsets(Insets.NONE) + .build() val processedRequest = processor.process(request) @@ -202,14 +223,18 @@ class RequestProcessorTest { } private fun makeHardwareBitmap(width: Int, height: Int): Bitmap { - val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1, - HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) + val buffer = + HardwareBuffer.create( + width, + height, + HardwareBuffer.RGBA_8888, + 1, + HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE + ) return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!! } - private fun Bitmap.equalsHardwareBitmapBundle(bundle: Bundle): Boolean { - val provided = bundleToHardwareBitmap(bundle) - return provided.hardwareBuffer == this.hardwareBuffer && - provided.colorSpace == this.colorSpace + private fun Bitmap.equalsHardwareBitmap(bitmap: Bitmap): Boolean { + return bitmap.hardwareBuffer == this.hardwareBuffer && bitmap.colorSpace == this.colorSpace } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt index 99c79b0365ae..f93501928844 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt @@ -35,8 +35,7 @@ import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.internal.util.ScreenshotHelper -import com.android.internal.util.ScreenshotHelper.ScreenshotRequest +import com.android.internal.util.ScreenshotRequest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY @@ -80,24 +79,39 @@ class TakeScreenshotServiceTest : SysuiTestCase() { private val flags = FakeFeatureFlags() private val topComponent = ComponentName(mContext, TakeScreenshotServiceTest::class.java) - private val service = TakeScreenshotService( - controller, userManager, devicePolicyManager, eventLogger, - notificationsController, mContext, Runnable::run, flags, requestProcessor) + private val service = + TakeScreenshotService( + controller, + userManager, + devicePolicyManager, + eventLogger, + notificationsController, + mContext, + Runnable::run, + flags, + requestProcessor + ) @Before fun setUp() { whenever(devicePolicyManager.resources).thenReturn(devicePolicyResourcesManager) - whenever(devicePolicyManager.getScreenCaptureDisabled( - /* admin component (null: any admin) */ isNull(), eq(UserHandle.USER_ALL))) + whenever( + devicePolicyManager.getScreenCaptureDisabled( + /* admin component (null: any admin) */ isNull(), + eq(UserHandle.USER_ALL) + ) + ) .thenReturn(false) whenever(userManager.isUserUnlocked).thenReturn(true) // Stub request processor as a synchronous no-op for tests with the flag enabled doAnswer { - val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest - val consumer: Consumer<ScreenshotRequest> = it.getArgument(1) - consumer.accept(request) - }.`when`(requestProcessor).processAsync(/* request= */ any(), /* callback= */ any()) + val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest + val consumer: Consumer<ScreenshotRequest> = it.getArgument(1) + consumer.accept(request) + } + .`when`(requestProcessor) + .processAsync(/* request= */ any(), /* callback= */ any()) // Flipped in selected test cases flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false) @@ -108,7 +122,8 @@ class TakeScreenshotServiceTest : SysuiTestCase() { /* className = */ null, /* token = */ null, application, - /* activityManager = */ null) + /* activityManager = */ null + ) } @Test @@ -125,63 +140,89 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen() { - val request = ScreenshotRequest( - TAKE_SCREENSHOT_FULLSCREEN, - SCREENSHOT_KEY_CHORD, - topComponent) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + .setTopComponent(topComponent) + .build() - service.handleRequest(request, { /* onSaved */ }, callback) + service.handleRequest(request, { /* onSaved */}, callback) - verify(controller, times(1)).takeScreenshotFullscreen( - eq(topComponent), - /* onSavedListener = */ any(), - /* requestCallback = */ any()) + verify(controller, times(1)) + .takeScreenshotFullscreen( + eq(topComponent), + /* onSavedListener = */ any(), + /* requestCallback = */ any() + ) assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1) val logEvent = eventLogger.get(0) - assertEquals("Expected SCREENSHOT_REQUESTED UiEvent", - logEvent.eventId, SCREENSHOT_REQUESTED_KEY_CHORD.id) - assertEquals("Expected supplied package name", - topComponent.packageName, eventLogger.get(0).packageName) + assertEquals( + "Expected SCREENSHOT_REQUESTED UiEvent", + logEvent.eventId, + SCREENSHOT_REQUESTED_KEY_CHORD.id + ) + assertEquals( + "Expected supplied package name", + topComponent.packageName, + eventLogger.get(0).packageName + ) } @Test fun takeScreenshotProvidedImage() { val bounds = Rect(50, 50, 150, 150) val bitmap = makeHardwareBitmap(100, 100) - val bitmapBundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(bitmap) - - val request = ScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW, - bitmapBundle, bounds, Insets.NONE, TASK_ID, USER_ID, topComponent) - - service.handleRequest(request, { /* onSaved */ }, callback) - verify(controller, times(1)).handleImageAsScreenshot( - argThat { b -> b.equalsHardwareBitmap(bitmap) }, - eq(bounds), - eq(Insets.NONE), eq(TASK_ID), eq(USER_ID), eq(topComponent), - /* onSavedListener = */ any(), /* requestCallback = */ any()) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OVERVIEW) + .setTopComponent(topComponent) + .setTaskId(TASK_ID) + .setUserId(USER_ID) + .setBitmap(bitmap) + .setBoundsOnScreen(bounds) + .setInsets(Insets.NONE) + .build() + + service.handleRequest(request, { /* onSaved */}, callback) + + verify(controller, times(1)) + .handleImageAsScreenshot( + argThat { b -> b.equalsHardwareBitmap(bitmap) }, + eq(bounds), + eq(Insets.NONE), + eq(TASK_ID), + eq(USER_ID), + eq(topComponent), + /* onSavedListener = */ any(), + /* requestCallback = */ any() + ) assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1) val logEvent = eventLogger.get(0) - assertEquals("Expected SCREENSHOT_REQUESTED_* UiEvent", - logEvent.eventId, SCREENSHOT_REQUESTED_OVERVIEW.id) - assertEquals("Expected supplied package name", - topComponent.packageName, eventLogger.get(0).packageName) + assertEquals( + "Expected SCREENSHOT_REQUESTED_* UiEvent", + logEvent.eventId, + SCREENSHOT_REQUESTED_OVERVIEW.id + ) + assertEquals( + "Expected supplied package name", + topComponent.packageName, + eventLogger.get(0).packageName + ) } @Test fun takeScreenshotFullscreen_userLocked() { whenever(userManager.isUserUnlocked).thenReturn(false) - val request = ScreenshotRequest( - TAKE_SCREENSHOT_FULLSCREEN, - SCREENSHOT_KEY_CHORD, - topComponent) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + .setTopComponent(topComponent) + .build() - service.handleRequest(request, { /* onSaved */ }, callback) + service.handleRequest(request, { /* onSaved */}, callback) verify(notificationsController, times(1)).notifyScreenshotError(anyInt()) verify(callback, times(1)).reportError() @@ -190,21 +231,24 @@ class TakeScreenshotServiceTest : SysuiTestCase() { @Test fun takeScreenshotFullscreen_screenCaptureDisabled_allUsers() { - whenever(devicePolicyManager.getScreenCaptureDisabled( - isNull(), eq(UserHandle.USER_ALL)) - ).thenReturn(true) + whenever(devicePolicyManager.getScreenCaptureDisabled(isNull(), eq(UserHandle.USER_ALL))) + .thenReturn(true) - whenever(devicePolicyResourcesManager.getString( - eq(SCREENSHOT_BLOCKED_BY_ADMIN), - /* Supplier<String> */ any(), - )).thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN") + whenever( + devicePolicyResourcesManager.getString( + eq(SCREENSHOT_BLOCKED_BY_ADMIN), + /* Supplier<String> */ + any(), + ) + ) + .thenReturn("SCREENSHOT_BLOCKED_BY_ADMIN") - val request = ScreenshotRequest( - TAKE_SCREENSHOT_FULLSCREEN, - SCREENSHOT_KEY_CHORD, - topComponent) + val request = + ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) + .setTopComponent(topComponent) + .build() - service.handleRequest(request, { /* onSaved */ }, callback) + service.handleRequest(request, { /* onSaved */}, callback) // error shown: Toast.makeText(...).show(), untestable verify(callback, times(1)).reportError() @@ -214,14 +258,20 @@ class TakeScreenshotServiceTest : SysuiTestCase() { private fun Bitmap.equalsHardwareBitmap(other: Bitmap): Boolean { return config == HARDWARE && - other.config == HARDWARE && - hardwareBuffer == other.hardwareBuffer && - colorSpace == other.colorSpace + other.config == HARDWARE && + hardwareBuffer == other.hardwareBuffer && + colorSpace == other.colorSpace } /** A hardware Bitmap is mandated by use of ScreenshotHelper.HardwareBitmapBundler */ private fun makeHardwareBitmap(width: Int, height: Int): Bitmap { - val buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, 1, - HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) + val buffer = + HardwareBuffer.create( + width, + height, + HardwareBuffer.RGBA_8888, + 1, + HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE + ) return Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!! } diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java index 3fa0ab69d67c..e6abc4c90fac 100644 --- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java +++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java @@ -391,7 +391,7 @@ public class SystemActionPerformer { private boolean takeScreenshot() { ScreenshotHelper screenshotHelper = (mScreenshotHelperSupplier != null) ? mScreenshotHelperSupplier.get() : new ScreenshotHelper(mContext); - screenshotHelper.takeScreenshot(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, + screenshotHelper.takeScreenshot( WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null); return true; diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java index 4fd739ca5e3e..4b0ae1be9d2f 100644 --- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java +++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java @@ -16,6 +16,9 @@ package com.android.server.app; +import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER; +import static android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -33,7 +36,6 @@ import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; import android.net.Uri; -import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.service.games.CreateGameSessionRequest; @@ -50,7 +52,6 @@ import android.text.TextUtils; import android.util.Slog; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost.SurfacePackage; -import android.view.WindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -59,6 +60,7 @@ import com.android.internal.infra.ServiceConnector; import com.android.internal.infra.ServiceConnector.ServiceLifecycleCallbacks; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ScreenshotHelper; +import com.android.internal.util.ScreenshotRequest; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerInternal; import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener; @@ -861,8 +863,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan Slog.w(TAG, "Could not get bitmap for id: " + taskId); callback.complete(GameScreenshotResult.createInternalErrorResult()); } else { - final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle( - bitmap); final RunningTaskInfo runningTaskInfo = mGameTaskInfoProvider.getRunningTaskInfo(taskId); if (runningTaskInfo == null) { @@ -877,11 +877,17 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan callback.complete(GameScreenshotResult.createSuccessResult()); } }; - mScreenshotHelper.provideScreenshot(bundle, crop, Insets.NONE, taskId, - mUserHandle.getIdentifier(), gameSessionRecord.getComponentName(), - WindowManager.ScreenshotSource.SCREENSHOT_OTHER, - BackgroundThread.getHandler(), - completionConsumer); + ScreenshotRequest request = new ScreenshotRequest.Builder( + TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER) + .setTopComponent(gameSessionRecord.getComponentName()) + .setTaskId(taskId) + .setUserId(mUserHandle.getIdentifier()) + .setBitmap(bitmap) + .setBoundsOnScreen(crop) + .setInsets(Insets.NONE) + .build(); + mScreenshotHelper.takeScreenshot( + request, BackgroundThread.getHandler(), completionConsumer); } }); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5f705ff7cfd4..97aa02fe396c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -711,7 +711,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { handleRingerChordGesture(); break; case MSG_SCREENSHOT_CHORD: - handleScreenShot(msg.arg1, msg.arg2); + handleScreenShot(msg.arg1); break; } } @@ -1502,9 +1502,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { || mShortPressOnStemPrimaryBehavior != SHORT_PRESS_PRIMARY_NOTHING; } - private void interceptScreenshotChord(int type, int source, long pressDelay) { + private void interceptScreenshotChord(int source, long pressDelay) { mHandler.removeMessages(MSG_SCREENSHOT_CHORD); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, type, source), + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SCREENSHOT_CHORD, source), pressDelay); } @@ -1574,9 +1574,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private void handleScreenShot(@WindowManager.ScreenshotType int type, - @WindowManager.ScreenshotSource int source) { - mDefaultDisplayPolicy.takeScreenshot(type, source); + private void handleScreenShot(@WindowManager.ScreenshotSource int source) { + mDefaultDisplayPolicy.takeScreenshot(TAKE_SCREENSHOT_FULLSCREEN, source); } @Override @@ -2173,7 +2172,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override void execute() { mPowerKeyHandled = true; - interceptScreenshotChord(TAKE_SCREENSHOT_FULLSCREEN, + interceptScreenshotChord( SCREENSHOT_KEY_CHORD, getScreenshotChordLongPressDelay()); } @Override @@ -2867,8 +2866,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; case KeyEvent.KEYCODE_S: if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) { - interceptScreenshotChord( - TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); + interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); return key_consumed; } break; @@ -3252,8 +3250,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; case KeyEvent.KEYCODE_SYSRQ: if (down && repeatCount == 0) { - interceptScreenshotChord( - TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); + interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); } return true; } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 0bb4022d9289..f8fd2b953c20 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -142,6 +142,7 @@ import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.statusbar.LetterboxDetails; import com.android.internal.util.ScreenshotHelper; +import com.android.internal.util.ScreenshotRequest; import com.android.internal.util.function.TriConsumer; import com.android.internal.view.AppearanceRegion; import com.android.internal.widget.PointerLocationView; @@ -2666,8 +2667,9 @@ public class DisplayPolicy { */ public void takeScreenshot(int screenshotType, int source) { if (mScreenshotHelper != null) { - mScreenshotHelper.takeScreenshot(screenshotType, - source, mHandler, null /* completionConsumer */); + ScreenshotRequest request = + new ScreenshotRequest.Builder(screenshotType, source).build(); + mScreenshotHelper.takeScreenshot(request, mHandler, null /* completionConsumer */); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java index e4f9eaf091e9..9b23f8b3fcab 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java @@ -1089,8 +1089,7 @@ public final class GameServiceProviderInstanceImplTest { Consumer<Uri> consumer = invocation.getArgument(invocation.getArguments().length - 1); consumer.accept(Uri.parse("a/b.png")); return null; - }).when(mMockScreenshotHelper).provideScreenshot( - any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any()); + }).when(mMockScreenshotHelper).takeScreenshot(any(), any(), any()); mGameServiceProviderInstance.start(); startTask(taskId, GAME_A_MAIN_ACTIVITY); mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java index c15f6a9c3d66..5792ecb5f743 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java @@ -17,7 +17,6 @@ package com.android.server.accessibility; import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS; -import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; @@ -301,9 +300,7 @@ public class SystemActionPerformerTest { mSystemActionPerformer.performSystemAction( AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT); verify(mMockScreenshotHelper).takeScreenshot( - eq(TAKE_SCREENSHOT_FULLSCREEN), - eq(SCREENSHOT_ACCESSIBILITY_ACTIONS), - any(Handler.class), any()); + eq(SCREENSHOT_ACCESSIBILITY_ACTIONS), any(Handler.class), any()); } // PendingIntent is a final class and cannot be mocked. So we are using this |