summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mark Renouf <mrenouf@google.com> 2022-08-04 14:55:24 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-08-04 14:55:24 +0000
commit7ef79cd9f7464e6e40b01fd46f1e7e71a4c93a64 (patch)
tree6983e24036b2add6a42ebd656e17755982e5e789
parent59acfb541e3511e40aaceb45c68c9e39c89c5625 (diff)
parent9ae4e8626bc00757d9a71fa75a43057f69e97041 (diff)
Merge "Screenshot request processor" into tm-qpr-dev am: 9ae4e8626b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19261492 Change-Id: I7d758e8b1560ddc967b3250bdcd972dcefb697d7 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt106
4 files changed, 194 insertions, 1 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 7e88946cb8c3..d4799883129e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -217,6 +217,10 @@ public class Flags {
public static final BooleanFlag NEW_BACK_AFFORDANCE =
new BooleanFlag(1203, false /* default */, false /* teamfood */);
+ // 1300 - screenshots
+
+ public static final BooleanFlag SCREENSHOT_REQUEST_PROCESSOR = new BooleanFlag(1300, false);
+
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
// | |
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
new file mode 100644
index 000000000000..beb54c85e021
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 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.systemui.screenshot
+
+import android.net.Uri
+import android.util.Log
+import android.view.WindowManager.ScreenshotType
+import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
+import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
+import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
+import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
+import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/**
+ * Processes a screenshot request sent from {@link ScreenshotHelper}.
+ */
+@SysUISingleton
+internal class RequestProcessor @Inject constructor(
+ private val controller: ScreenshotController,
+) {
+ fun processRequest(
+ @ScreenshotType type: Int,
+ onSavedListener: Consumer<Uri>,
+ request: ScreenshotRequest,
+ callback: RequestCallback
+ ) {
+
+ if (type == TAKE_SCREENSHOT_PROVIDED_IMAGE) {
+ val image = HardwareBitmapBundler.bundleToHardwareBitmap(request.bitmapBundle)
+
+ controller.handleImageAsScreenshot(
+ image, request.boundsInScreen, request.insets,
+ request.taskId, request.userId, request.topComponent, onSavedListener, callback
+ )
+ return
+ }
+
+ when (type) {
+ TAKE_SCREENSHOT_FULLSCREEN ->
+ controller.takeScreenshotFullscreen(null, onSavedListener, callback)
+ TAKE_SCREENSHOT_SELECTED_REGION ->
+ controller.takeScreenshotPartial(null, onSavedListener, callback)
+ else -> Log.w(TAG, "Invalid screenshot option: $type")
+ }
+ }
+
+ companion object {
+ const val TAG: String = "RequestProcessor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 32d82037efb9..f1f0223632b7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -21,6 +21,7 @@ import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
+import static com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SERVICE;
@@ -57,6 +58,8 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FlagListenable.FlagEvent;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -75,6 +78,8 @@ public class TakeScreenshotService extends Service {
private final Handler mHandler;
private final Context mContext;
private final @Background Executor mBgExecutor;
+ private final RequestProcessor mProcessor;
+ private final FeatureFlags mFeatureFlags;
private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() {
@Override
@@ -104,7 +109,8 @@ public class TakeScreenshotService extends Service {
public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
DevicePolicyManager devicePolicyManager, UiEventLogger uiEventLogger,
ScreenshotNotificationsController notificationsController, Context context,
- @Background Executor bgExecutor) {
+ @Background Executor bgExecutor, FeatureFlags featureFlags,
+ RequestProcessor processor) {
if (DEBUG_SERVICE) {
Log.d(TAG, "new " + this);
}
@@ -116,6 +122,9 @@ public class TakeScreenshotService extends Service {
mNotificationsController = notificationsController;
mContext = context;
mBgExecutor = bgExecutor;
+ mFeatureFlags = featureFlags;
+ mFeatureFlags.addListener(SCREENSHOT_REQUEST_PROCESSOR, FlagEvent::requestNoRestart);
+ mProcessor = processor;
}
@Override
@@ -218,6 +227,12 @@ public class TakeScreenshotService extends Service {
mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()), 0,
topComponent == null ? "" : topComponent.getPackageName());
+ if (mFeatureFlags.isEnabled(SCREENSHOT_REQUEST_PROCESSOR)) {
+ Log.d(TAG, "handleMessage: Using request processor");
+ mProcessor.processRequest(msg.what, uriConsumer, screenshotRequest, requestCallback);
+ return true;
+ }
+
switch (msg.what) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (DEBUG_SERVICE) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
new file mode 100644
index 000000000000..002f23a9ed6d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 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.systemui.screenshot
+
+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.net.Uri
+import android.view.WindowManager
+import android.view.WindowManager.ScreenshotSource
+import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
+import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
+import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+import org.junit.Test
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.isNull
+
+class RequestProcessorTest {
+ private val controller = mock<ScreenshotController>()
+ private val bitmapCaptor = argumentCaptor<Bitmap>()
+
+ @Test
+ fun testFullScreenshot() {
+ val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_KEY_CHORD)
+ val onSavedListener = mock<Consumer<Uri>>()
+ val callback = mock<RequestCallback>()
+ val processor = RequestProcessor(controller)
+
+ processor.processRequest(WindowManager.TAKE_SCREENSHOT_FULLSCREEN, onSavedListener,
+ request, callback)
+
+ verify(controller).takeScreenshotFullscreen(/* topComponent */ isNull(),
+ eq(onSavedListener), eq(callback))
+ }
+
+ @Test
+ fun testSelectedRegionScreenshot() {
+ val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_KEY_CHORD)
+ val onSavedListener = mock<Consumer<Uri>>()
+ val callback = mock<RequestCallback>()
+ val processor = RequestProcessor(controller)
+
+ processor.processRequest(WindowManager.TAKE_SCREENSHOT_SELECTED_REGION, onSavedListener,
+ request, callback)
+
+ verify(controller).takeScreenshotPartial(/* topComponent */ isNull(),
+ eq(onSavedListener), eq(callback))
+ }
+
+ @Test
+ fun testProvidedImageScreenshot() {
+ val taskId = 1111
+ val userId = 2222
+ val bounds = Rect(50, 50, 150, 150)
+ val topComponent = ComponentName("test", "test")
+ val processor = RequestProcessor(controller)
+
+ val buffer = HardwareBuffer.create(100, 100, HardwareBuffer.RGBA_8888, 1,
+ HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE)
+ val bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB))!!
+ val bitmapBundle = HardwareBitmapBundler.hardwareBitmapToBundle(bitmap)
+
+ val request = ScreenshotRequest(ScreenshotSource.SCREENSHOT_OTHER, bitmapBundle,
+ bounds, Insets.NONE, taskId, userId, topComponent)
+
+ val onSavedListener = mock<Consumer<Uri>>()
+ val callback = mock<RequestCallback>()
+
+ processor.processRequest(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, onSavedListener,
+ request, callback)
+
+ verify(controller).handleImageAsScreenshot(
+ bitmapCaptor.capture(), eq(bounds), eq(Insets.NONE), eq(taskId), eq(userId),
+ eq(topComponent), eq(onSavedListener), eq(callback)
+ )
+
+ assertThat(bitmapCaptor.value.equalsHardwareBitmap(bitmap)).isTrue()
+ }
+
+ private fun Bitmap.equalsHardwareBitmap(bitmap: Bitmap): Boolean {
+ return bitmap.hardwareBuffer == this.hardwareBuffer &&
+ bitmap.colorSpace == this.colorSpace
+ }
+}