Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47d3c329 authored by Miranda Kephart's avatar Miranda Kephart Committed by Android (Google) Code Review
Browse files

Merge "Switch all screenshot saving paths to ImageExporter" into main

parents 1c55e509 ecb2ea0a
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -590,6 +590,16 @@ flag {
    }
    }
}
}


flag {
    name: "screenshot_save_image_exporter"
    namespace: "systemui"
    description: "Save all screenshots using ImageExporter"
    bug: "352308052"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
flag {
   name: "run_fingerprint_detect_on_dismissible_keyguard"
   name: "run_fingerprint_detect_on_dismissible_keyguard"
   namespace: "systemui"
   namespace: "systemui"
+45 −53
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;


import static com.android.systemui.Flags.screenshotPrivateProfileAccessibilityAnnouncementFix;
import static com.android.systemui.Flags.screenshotPrivateProfileAccessibilityAnnouncementFix;
import static com.android.systemui.Flags.screenshotSaveImageExporter;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT;
@@ -230,13 +231,6 @@ public class ScreenshotController implements ScreenshotHandler {
    private String mPackageName = "";
    private String mPackageName = "";
    private final BroadcastReceiver mCopyBroadcastReceiver;
    private final BroadcastReceiver mCopyBroadcastReceiver;


    // When false, the screenshot is taken without showing the ui. Note that this only applies to
    // external displays, as on the default one the UI should **always** be shown.
    // This is needed in case of screenshot during display mirroring, as adding another window to
    // the external display makes mirroring stop.
    // When there is a way to distinguish between displays that are mirroring or extending, this
    // can be removed and we can directly show the ui only in the extended case.
    private final Boolean mShowUIOnExternalDisplay;
    /** Tracks config changes that require re-creating UI */
    /** Tracks config changes that require re-creating UI */
    private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
    private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
            ActivityInfo.CONFIG_ORIENTATION
            ActivityInfo.CONFIG_ORIENTATION
@@ -272,8 +266,7 @@ public class ScreenshotController implements ScreenshotHandler {
            MessageContainerController messageContainerController,
            MessageContainerController messageContainerController,
            Provider<ScreenshotSoundController> screenshotSoundController,
            Provider<ScreenshotSoundController> screenshotSoundController,
            AnnouncementResolver announcementResolver,
            AnnouncementResolver announcementResolver,
            @Assisted Display display,
            @Assisted Display display
            @Assisted boolean showUIOnExternalDisplay
    ) {
    ) {
        mScreenshotSmartActions = screenshotSmartActions;
        mScreenshotSmartActions = screenshotSmartActions;
        mNotificationsController = screenshotNotificationsControllerFactory.create(
        mNotificationsController = screenshotNotificationsControllerFactory.create(
@@ -347,7 +340,6 @@ public class ScreenshotController implements ScreenshotHandler {
        mBroadcastDispatcher.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
        mBroadcastDispatcher.registerReceiver(mCopyBroadcastReceiver, new IntentFilter(
                        ClipboardOverlayController.COPY_OVERLAY_ACTION), null, null,
                        ClipboardOverlayController.COPY_OVERLAY_ACTION), null, null,
                Context.RECEIVER_NOT_EXPORTED, ClipboardOverlayController.SELF_PERMISSION);
                Context.RECEIVER_NOT_EXPORTED, ClipboardOverlayController.SELF_PERMISSION);
        mShowUIOnExternalDisplay = showUIOnExternalDisplay;
    }
    }


    @Override
    @Override
@@ -381,7 +373,7 @@ public class ScreenshotController implements ScreenshotHandler {
            Log.w(TAG, "User setup not complete, displaying toast only");
            Log.w(TAG, "User setup not complete, displaying toast only");
            // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
            // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
            // and sharing shouldn't be exposed to the user.
            // and sharing shouldn't be exposed to the user.
            saveScreenshotAndToast(screenshot.getUserHandle(), finisher);
            saveScreenshotAndToast(screenshot, finisher);
            return;
            return;
        }
        }


@@ -397,17 +389,15 @@ public class ScreenshotController implements ScreenshotHandler {


        prepareViewForNewScreenshot(screenshot, oldPackageName);
        prepareViewForNewScreenshot(screenshot, oldPackageName);


        if (!shouldShowUi()) {
            saveScreenshotInWorkerThread(
                    screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady,
                    (ignored) -> {
                    });
            return;
        }

        final UUID requestId;
        final UUID requestId;
        requestId = mActionsController.setCurrentScreenshot(screenshot);
        requestId = mActionsController.setCurrentScreenshot(screenshot);
        saveScreenshotInBackground(screenshot, requestId, finisher);
        saveScreenshotInBackground(screenshot, requestId, finisher, result -> {
            if (result.uri != null) {
                ScreenshotSavedResult savedScreenshot = new ScreenshotSavedResult(
                        result.uri, screenshot.getUserOrDefault(), result.timestamp);
                mActionsController.setCompletedScreenshot(requestId, savedScreenshot);
            }
        });


        if (screenshot.getTaskId() >= 0) {
        if (screenshot.getTaskId() >= 0) {
            mAssistContentRequester.requestAssistContent(
            mAssistContentRequester.requestAssistContent(
@@ -453,10 +443,6 @@ public class ScreenshotController implements ScreenshotHandler {
                (v, insets) -> WindowInsets.CONSUMED);
                (v, insets) -> WindowInsets.CONSUMED);
    }
    }


    private boolean shouldShowUi() {
        return mDisplay.getDisplayId() == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay;
    }

    void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
    void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) {
        withWindowAttached(() -> {
        withWindowAttached(() -> {
            if (screenshotPrivateProfileAccessibilityAnnouncementFix()) {
            if (screenshotPrivateProfileAccessibilityAnnouncementFix()) {
@@ -724,20 +710,30 @@ public class ScreenshotController implements ScreenshotHandler {
     * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
     * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
     * failure).
     * failure).
     */
     */
    private void saveScreenshotAndToast(UserHandle owner, Consumer<Uri> finisher) {
    private void saveScreenshotAndToast(ScreenshotData screenshot, Consumer<Uri> finisher) {
        // Play the shutter sound to notify that we've taken a screenshot
        // Play the shutter sound to notify that we've taken a screenshot
        playCameraSoundIfNeeded();
        playCameraSoundIfNeeded();


        if (screenshotSaveImageExporter()) {
            saveScreenshotInBackground(screenshot, UUID.randomUUID(), finisher, result -> {
                if (result.uri != null) {
                    mScreenshotHandler.post(() -> Toast.makeText(mContext,
                            R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
                }
            });
        } else {
            saveScreenshotInWorkerThread(
            saveScreenshotInWorkerThread(
                owner,
                    screenshot.getUserHandle(),
                    /* onComplete */ finisher,
                    /* onComplete */ finisher,
                    /* actionsReadyListener */ imageData -> {
                    /* actionsReadyListener */ imageData -> {
                        if (DEBUG_CALLBACK) {
                        if (DEBUG_CALLBACK) {
                        Log.d(TAG, "returning URI to finisher (Consumer<URI>): " + imageData.uri);
                            Log.d(TAG,
                                    "returning URI to finisher (Consumer<URI>): " + imageData.uri);
                        }
                        }
                        finisher.accept(imageData.uri);
                        finisher.accept(imageData.uri);
                        if (imageData.uri == null) {
                        if (imageData.uri == null) {
                        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, mPackageName);
                            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0,
                                    mPackageName);
                            mNotificationsController.notifyScreenshotError(
                            mNotificationsController.notifyScreenshotError(
                                    R.string.screenshot_failed_to_save_text);
                                    R.string.screenshot_failed_to_save_text);
                        } else {
                        } else {
@@ -748,6 +744,7 @@ public class ScreenshotController implements ScreenshotHandler {
                    },
                    },
                    null);
                    null);
        }
        }
    }


    /**
    /**
     * Starts the animation after taking the screenshot
     * Starts the animation after taking the screenshot
@@ -819,8 +816,8 @@ public class ScreenshotController implements ScreenshotHandler {
        mScreenshotHandler.cancelTimeout();
        mScreenshotHandler.cancelTimeout();
    }
    }


    private void saveScreenshotInBackground(
    private void saveScreenshotInBackground(ScreenshotData screenshot, UUID requestId,
            ScreenshotData screenshot, UUID requestId, Consumer<Uri> finisher) {
            Consumer<Uri> finisher, Consumer<ImageExporter.Result> onResult) {
        ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
        ListenableFuture<ImageExporter.Result> future = mImageExporter.export(mBgExecutor,
                requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
                requestId, screenshot.getBitmap(), screenshot.getUserOrDefault(),
                mDisplay.getDisplayId());
                mDisplay.getDisplayId());
@@ -829,10 +826,7 @@ public class ScreenshotController implements ScreenshotHandler {
                ImageExporter.Result result = future.get();
                ImageExporter.Result result = future.get();
                Log.d(TAG, "Saved screenshot: " + result);
                Log.d(TAG, "Saved screenshot: " + result);
                logScreenshotResultStatus(result.uri, screenshot.getUserHandle());
                logScreenshotResultStatus(result.uri, screenshot.getUserHandle());
                if (result.uri != null) {
                onResult.accept(result);
                    mActionsController.setCompletedScreenshot(requestId, new ScreenshotSavedResult(
                            result.uri, screenshot.getUserOrDefault(), result.timestamp));
                }
                if (DEBUG_CALLBACK) {
                if (DEBUG_CALLBACK) {
                    Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) "
                    Log.d(TAG, "finished background processing, Calling (Consumer<Uri>) "
                            + "finisher.accept(\"" + result.uri + "\"");
                            + "finisher.accept(\"" + result.uri + "\"");
@@ -1028,9 +1022,7 @@ public class ScreenshotController implements ScreenshotHandler {
         * Creates an instance of the controller for that specific display.
         * Creates an instance of the controller for that specific display.
         *
         *
         * @param display                 display to capture
         * @param display                 display to capture
         * @param showUIOnExternalDisplay Whether the UI should be shown if this is an external
         *                                display.
         */
         */
        ScreenshotController create(Display display, boolean showUIOnExternalDisplay);
        ScreenshotController create(Display display);
    }
    }
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -219,7 +219,7 @@ constructor(
    }
    }


    private fun getScreenshotController(display: Display): ScreenshotController {
    private fun getScreenshotController(display: Display): ScreenshotController {
        val controller = screenshotController ?: screenshotControllerFactory.create(display, false)
        val controller = screenshotController ?: screenshotControllerFactory.create(display)
        screenshotController = controller
        screenshotController = controller
        return controller
        return controller
    }
    }
+6 −6
Original line number Original line Diff line number Diff line
@@ -69,7 +69,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {


    @Before
    @Before
    fun setUp() {
    fun setUp() {
        whenever(controllerFactory.create(any(), any())).thenReturn(controller)
        whenever(controllerFactory.create(any())).thenReturn(controller)
        whenever(notificationControllerFactory.create(eq(0))).thenReturn(notificationsController0)
        whenever(notificationControllerFactory.create(eq(0))).thenReturn(notificationsController0)
        whenever(notificationControllerFactory.create(eq(1))).thenReturn(notificationsController1)
        whenever(notificationControllerFactory.create(eq(1))).thenReturn(notificationsController1)
    }
    }
@@ -83,8 +83,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
            val onSaved = { _: Uri? -> }
            val onSaved = { _: Uri? -> }
            screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)
            screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback)


            verify(controllerFactory).create(eq(internalDisplay), any())
            verify(controllerFactory).create(eq(internalDisplay))
            verify(controllerFactory, never()).create(eq(externalDisplay), any())
            verify(controllerFactory, never()).create(eq(externalDisplay))


            val capturer = ArgumentCaptor<ScreenshotData>()
            val capturer = ArgumentCaptor<ScreenshotData>()


@@ -118,8 +118,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
                callback
                callback
            )
            )


            verify(controllerFactory).create(eq(internalDisplay), any())
            verify(controllerFactory).create(eq(internalDisplay))
            verify(controllerFactory, never()).create(eq(externalDisplay), any())
            verify(controllerFactory, never()).create(eq(externalDisplay))


            val capturer = ArgumentCaptor<ScreenshotData>()
            val capturer = ArgumentCaptor<ScreenshotData>()


@@ -151,7 +151,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() {
    @Test
    @Test
    fun executeScreenshots_allowedTypes_allCaptured() =
    fun executeScreenshots_allowedTypes_allCaptured() =
        testScope.runTest {
        testScope.runTest {
            whenever(controllerFactory.create(any(), any())).thenReturn(controller)
            whenever(controllerFactory.create(any())).thenReturn(controller)


            setDisplays(
            setDisplays(
                display(TYPE_INTERNAL, id = 0),
                display(TYPE_INTERNAL, id = 0),