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

Commit e538f40b authored by Miranda Kephart's avatar Miranda Kephart Committed by Automerger Merge Worker
Browse files

Merge "Keep screenshot process bound" into rvc-dev am: c8f22bee

Change-Id: Ie1d005ab6719ac9128a3880ca0d62406a22f809c
parents d92f5b3d c8f22bee
Loading
Loading
Loading
Loading
+85 −62
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@ import java.util.function.Consumer;

public class ScreenshotHelper {

    public static final int SCREENSHOT_MSG_URI = 1;
    public static final int SCREENSHOT_MSG_PROCESS_COMPLETE = 2;

    /**
     * Describes a screenshot request (to make it easier to pass data through to the handler).
     */
@@ -135,6 +138,7 @@ public class ScreenshotHelper {
    private final int SCREENSHOT_TIMEOUT_MS = 10000;

    private final Object mScreenshotLock = new Object();
    private IBinder mScreenshotService = null;
    private ServiceConnection mScreenshotConnection = null;
    private final Context mContext;

@@ -251,58 +255,64 @@ public class ScreenshotHelper {
    private void takeScreenshot(final int screenshotType, long timeoutMs, @NonNull Handler handler,
            ScreenshotRequest screenshotRequest, @Nullable Consumer<Uri> completionConsumer) {
        synchronized (mScreenshotLock) {
            if (mScreenshotConnection != null) {
                return;
            }
            final ComponentName serviceComponent = ComponentName.unflattenFromString(
                    mContext.getResources().getString(
                            com.android.internal.R.string.config_screenshotServiceComponent));
            final Intent serviceIntent = new Intent();

            final Runnable mScreenshotTimeout = new Runnable() {
                @Override
                public void run() {
            final Runnable mScreenshotTimeout = () -> {
                synchronized (mScreenshotLock) {
                    if (mScreenshotConnection != null) {
                        mContext.unbindService(mScreenshotConnection);
                        mScreenshotConnection = null;
                        mScreenshotService = null;
                        notifyScreenshotError();
                    }
                }
                if (completionConsumer != null) {
                    completionConsumer.accept(null);
                }
                }
            };

            serviceIntent.setComponent(serviceComponent);
            ServiceConnection conn = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    synchronized (mScreenshotLock) {
                        if (mScreenshotConnection != this) {
                            return;
                        }
                        Messenger messenger = new Messenger(service);
            Message msg = Message.obtain(null, screenshotType, screenshotRequest);
                        final ServiceConnection myConn = this;
            final ServiceConnection myConn = mScreenshotConnection;
            Handler h = new Handler(handler.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case SCREENSHOT_MSG_URI:
                            if (completionConsumer != null) {
                                completionConsumer.accept((Uri) msg.obj);
                            }
                            handler.removeCallbacks(mScreenshotTimeout);
                            break;
                        case SCREENSHOT_MSG_PROCESS_COMPLETE:
                            synchronized (mScreenshotLock) {
                                if (mScreenshotConnection == myConn) {
                                    mContext.unbindService(mScreenshotConnection);
                                    mScreenshotConnection = null;
                                        handler.removeCallbacks(mScreenshotTimeout);
                                    mScreenshotService = null;
                                }
                            }
                                if (completionConsumer != null) {
                                    completionConsumer.accept((Uri) msg.obj);
                            break;
                    }
                }
            };
            msg.replyTo = new Messenger(h);

            if (mScreenshotConnection == null) {
                final ComponentName serviceComponent = ComponentName.unflattenFromString(
                        mContext.getResources().getString(
                                com.android.internal.R.string.config_screenshotServiceComponent));
                final Intent serviceIntent = new Intent();

                serviceIntent.setComponent(serviceComponent);
                ServiceConnection conn = new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {
                        synchronized (mScreenshotLock) {
                            if (mScreenshotConnection != this) {
                                return;
                            }
                            mScreenshotService = service;
                            Messenger messenger = new Messenger(mScreenshotService);

                            try {
                                messenger.send(msg);
                            } catch (RemoteException e) {
@@ -320,6 +330,7 @@ public class ScreenshotHelper {
                            if (mScreenshotConnection != null) {
                                mContext.unbindService(mScreenshotConnection);
                                mScreenshotConnection = null;
                                mScreenshotService = null;
                                handler.removeCallbacks(mScreenshotTimeout);
                                notifyScreenshotError();
                            }
@@ -327,11 +338,23 @@ public class ScreenshotHelper {
                    }
                };
                if (mContext.bindServiceAsUser(serviceIntent, conn,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                        UserHandle.CURRENT)) {
                    mScreenshotConnection = conn;
                    handler.postDelayed(mScreenshotTimeout, timeoutMs);
                }
            } else {
                Messenger messenger = new Messenger(mScreenshotService);
                try {
                    messenger.send(msg);
                } catch (RemoteException e) {
                    Log.e(TAG, "Couldn't take screenshot: " + e);
                    if (completionConsumer != null) {
                        completionConsumer.accept(null);
                    }
                }
                handler.postDelayed(mScreenshotTimeout, timeoutMs);
            }
        }
    }

+26 −12
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import android.graphics.Region;
import android.graphics.drawable.Icon;
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -188,7 +187,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
    private final ImageView mDismissImage;

    private Bitmap mScreenBitmap;
    private SaveImageInBackgroundTask mSaveInBgTask;
    private Animator mScreenshotAnimation;
    private Runnable mOnCompleteRunnable;
    private boolean mInDarkMode = false;

    private float mScreenshotOffsetXPx;
@@ -197,8 +198,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
    private float mDismissButtonSize;
    private float mCornerSizeX;

    private AsyncTask<Void, Void, Void> mSaveInBgTask;

    private MediaActionSound mCameraSound;

    // standard material ease
@@ -211,6 +210,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
                case MESSAGE_CORNER_TIMEOUT:
                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
                    GlobalScreenshot.this.clearScreenshot("timeout");
                    mOnCompleteRunnable.run();
                    break;
                default:
                    break;
@@ -252,6 +252,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
        mDismissButton.setOnClickListener(view -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
            clearScreenshot("dismiss_button");
            mOnCompleteRunnable.run();
        });
        mDismissImage = mDismissButton.findViewById(R.id.global_screenshot_dismiss_image);

@@ -325,19 +326,19 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
        data.finisher = finisher;
        data.mActionsReadyListener = actionsReadyListener;
        data.createDeleteAction = false;

        if (mSaveInBgTask != null) {
            mSaveInBgTask.cancel(false);
            mSaveInBgTask.ignoreResult();
        }

        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
        mSaveInBgTask.execute();
    }

    /**
     * Takes a screenshot of the current display and shows an animation.
     */
    private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {
        clearScreenshot("new screenshot requested");

        int rot = mDisplay.getRotation();
        int width = crop.width();
        int height = crop.height();
@@ -349,10 +350,12 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset

    private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect) {
        mScreenBitmap = screenshot;

        if (mScreenBitmap == null) {
            mNotificationsController.notifyScreenshotError(
                    R.string.screenshot_failed_to_capture_text);
            finisher.accept(null);
            mOnCompleteRunnable.run();
            return;
        }

@@ -366,11 +369,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
        mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);

        // Start the post-screenshot animation
        startAnimation(finisher, screenRect.width(), screenRect.height(),
                screenRect);
        startAnimation(finisher, screenRect.width(), screenRect.height(), screenRect);
    }

    void takeScreenshot(Consumer<Uri> finisher) {
    void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
        clearScreenshot("new screenshot requested");
        mOnCompleteRunnable = onComplete;

        mDisplay.getRealMetrics(mDisplayMetrics);
        takeScreenshot(
                finisher,
@@ -378,9 +383,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
    }

    void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
            Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
            Insets visibleInsets, int taskId, Consumer<Uri> finisher, Runnable onComplete) {
        // TODO use taskId and visibleInsets
        clearScreenshot("new screenshot requested");
        mOnCompleteRunnable = onComplete;

        takeScreenshot(screenshot, finisher, screenshotScreenBounds);
    }

@@ -388,7 +395,10 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
     * Displays a screenshot selector
     */
    @SuppressLint("ClickableViewAccessibility")
    void takeScreenshotPartial(final Consumer<Uri> finisher) {
    void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) {
        clearScreenshot("new screenshot requested");
        mOnCompleteRunnable = onComplete;

        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
        mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
            @Override
@@ -660,6 +670,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
                    () -> {
                        mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
                        clearScreenshot("chip tapped");
                        mOnCompleteRunnable.run();
                    });
            mActionsView.addView(actionChip);
        }
@@ -671,6 +682,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
        shareChip.setPendingIntent(imageData.shareAction.actionIntent, () -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
            clearScreenshot("chip tapped");
            mOnCompleteRunnable.run();
        });
        mActionsView.addView(shareChip);

@@ -681,6 +693,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
        editChip.setPendingIntent(imageData.editAction.actionIntent, () -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
            clearScreenshot("chip tapped");
            mOnCompleteRunnable.run();
        });
        mActionsView.addView(editChip);

@@ -689,6 +702,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
                imageData.editAction.actionIntent.send();
                mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
                clearScreenshot("screenshot preview tapped");
                mOnCompleteRunnable.run();
            } catch (PendingIntent.CanceledException e) {
                Log.e(TAG, "Intent cancelled", e);
            }
+13 −0
Original line number Diff line number Diff line
@@ -230,6 +230,19 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
        return null;
    }

    /**
     * If we get a new screenshot request while this one is saving, we want to continue saving in
     * the background but not return anything.
     */
    void ignoreResult() {
        mParams.mActionsReadyListener = new GlobalScreenshot.ActionsReadyListener() {
            @Override
            void onActionsReady(GlobalScreenshot.SavedImageData imageData) {
                // do nothing
            }
        };
    }

    @Override
    protected void onCancelled(Void params) {
        // If we are cancelled while the task is running in the background, we may get null
+20 −9
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.screenshot;

import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -51,8 +54,15 @@ public class TakeScreenshotService extends Service {
        @Override
        public void handleMessage(Message msg) {
            final Messenger callback = msg.replyTo;
            Consumer<Uri> finisher = uri -> {
                Message reply = Message.obtain(null, 1, uri);
            Consumer<Uri> uriConsumer = uri -> {
                Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);
                try {
                    callback.send(reply);
                } catch (RemoteException e) {
                }
            };
            Runnable onComplete = () -> {
                Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);
                try {
                    callback.send(reply);
                } catch (RemoteException e) {
@@ -64,7 +74,8 @@ public class TakeScreenshotService extends Service {
            // animation and error notification.
            if (!mUserManager.isUserUnlocked()) {
                Log.w(TAG, "Skipping screenshot because storage is locked!");
                post(() -> finisher.accept(null));
                post(() -> uriConsumer.accept(null));
                post(onComplete);
                return;
            }

@@ -79,19 +90,19 @@ public class TakeScreenshotService extends Service {
            switch (msg.what) {
                case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                    if (useCornerFlow) {
                        mScreenshot.takeScreenshot(finisher);
                        mScreenshot.takeScreenshot(uriConsumer, onComplete);
                    } else {
                        mScreenshotLegacy.takeScreenshot(
                                finisher, screenshotRequest.getHasStatusBar(),
                                uriConsumer, screenshotRequest.getHasStatusBar(),
                                screenshotRequest.getHasNavBar());
                    }
                    break;
                case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
                    if (useCornerFlow) {
                        mScreenshot.takeScreenshotPartial(finisher);
                        mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
                    } else {
                        mScreenshotLegacy.takeScreenshotPartial(
                                finisher, screenshotRequest.getHasStatusBar(),
                                uriConsumer, screenshotRequest.getHasStatusBar(),
                                screenshotRequest.getHasNavBar());
                    }
                    break;
@@ -102,10 +113,10 @@ public class TakeScreenshotService extends Service {
                    int taskId = screenshotRequest.getTaskId();
                    if (useCornerFlow) {
                        mScreenshot.handleImageAsScreenshot(
                                screenshot, screenBounds, insets, taskId, finisher);
                                screenshot, screenBounds, insets, taskId, uriConsumer, onComplete);
                    } else {
                        mScreenshotLegacy.handleImageAsScreenshot(
                                screenshot, screenBounds, insets, taskId, finisher);
                                screenshot, screenBounds, insets, taskId, uriConsumer);
                    }
                    break;
                default: