Merge "Screenshot request processor" into tm-qpr-dev
This commit is contained in:
@@ -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 ==========================
|
||||
// | |
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user