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

Commit 6b330ef7 authored by Miranda Kephart's avatar Miranda Kephart
Browse files

Add shared transitions for screenshot->markup

Bug: 170138961
Bug: 159419046
Test: manual

Change-Id: I3a9c7487cbc36a4a7183030d2e3aa432958f7e1a
parent 246e9240
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ public class ChooserActivity extends ResolverActivity implements
     * To be used for shared element transition into this activity.
     * @hide
     */
    public static final String FIRST_IMAGE_PREVIEW_TRANSITION_NAME = "chooser_preview_image_1";
    public static final String FIRST_IMAGE_PREVIEW_TRANSITION_NAME = "screenshot_preview_image";

    private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions";

+48 −43
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;

import java.io.File;
import java.io.IOException;
@@ -98,11 +98,11 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
    private final String mScreenshotId;
    private final boolean mSmartActionsEnabled;
    private final Random mRandom = new Random();
    private final Supplier<ShareTransition> mSharedElementTransition;
    private final Supplier<ActionTransition> mSharedElementTransition;

    SaveImageInBackgroundTask(Context context, ScreenshotSmartActions screenshotSmartActions,
            ScreenshotController.SaveImageInBackgroundData data,
            Supplier<ShareTransition> sharedElementTransition) {
            Supplier<ActionTransition> sharedElementTransition) {
        mContext = context;
        mScreenshotSmartActions = screenshotSmartActions;
        mImageData = new ScreenshotController.SavedImageData();
@@ -239,7 +239,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
            mImageData.uri = uri;
            mImageData.smartActions = smartActions;
            mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
            mImageData.editAction = createEditAction(mContext, mContext.getResources(), uri);
            mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
            mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);

            mParams.mActionsReadyListener.onActionsReady(mImageData);
@@ -293,9 +293,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
     * Assumes that the action intent is sent immediately after being supplied.
     */
    @VisibleForTesting
    Supplier<ShareTransition> createShareAction(Context context, Resources r, Uri uri) {
    Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri uri) {
        return () -> {
            ShareTransition transition = mSharedElementTransition.get();
            ActionTransition transition = mSharedElementTransition.get();

            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
            // order to do some common work like dismissing the keyguard and sending
@@ -348,13 +348,15 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
                    Icon.createWithResource(r, R.drawable.ic_screenshot_share),
                    r.getString(com.android.internal.R.string.share), shareAction);

            transition.shareAction = shareActionBuilder.build();
            transition.action = shareActionBuilder.build();
            return transition;
        };
    }

    @VisibleForTesting
    Notification.Action createEditAction(Context context, Resources r, Uri uri) {
    Supplier<ActionTransition> createEditAction(Context context, Resources r, Uri uri) {
        return () -> {
            ActionTransition transition = mSharedElementTransition.get();
            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
            // order to do some common work like dismissing the keyguard and sending
            // closeSystemWindows
@@ -371,8 +373,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
            editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
                editIntent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                    context, 0, editIntent, PendingIntent.FLAG_IMMUTABLE,
                    transition.bundle, UserHandle.CURRENT);

            // Make sure pending intents for the system user are still unique across users
            // by setting the (otherwise unused) request code to the current user id.
@@ -393,7 +396,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
                    Icon.createWithResource(r, R.drawable.ic_screenshot_edit),
                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);

        return editActionBuilder.build();
            transition.action = editActionBuilder.build();
            return transition;
        };
    }

    @VisibleForTesting
+17 −12
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.util.DeviceConfigProxy;

import java.util.List;
@@ -111,17 +111,17 @@ public class ScreenshotController {
     */
    static class SavedImageData {
        public Uri uri;
        public Supplier<ShareTransition> shareTransition;
        public Notification.Action editAction;
        public Supplier<ActionTransition> shareTransition;
        public Supplier<ActionTransition> editTransition;
        public Notification.Action deleteAction;
        public List<Notification.Action> smartActions;

        /**
         * POD for shared element transition to share sheet.
         * POD for shared element transition.
         */
        static class ShareTransition {
        static class ActionTransition {
            public Bundle bundle;
            public Notification.Action shareAction;
            public Notification.Action action;
            public Runnable onCancelRunnable;
        }

@@ -131,7 +131,7 @@ public class ScreenshotController {
        public void reset() {
            uri = null;
            shareTransition = null;
            editAction = null;
            editTransition = null;
            deleteAction = null;
            smartActions = null;
        }
@@ -339,6 +339,10 @@ public class ScreenshotController {
        }
    }

    boolean isPendingSharedTransition() {
        return mScreenshotView.isPendingSharedTransition();
    }

    /**
     * Update resources on configuration change. Reinflate for theme/color changes.
     */
@@ -462,7 +466,7 @@ public class ScreenshotController {
                Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. "
                        + "(dismissing=" + mScreenshotView.isDismissing() + ")");
            }
            mScreenshotView.reset();
            reloadAssets();
        }

        mScreenBitmap = screenshot;
@@ -605,7 +609,7 @@ public class ScreenshotController {
        }

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

@@ -659,7 +663,7 @@ public class ScreenshotController {
     * Supplies the necessary bits for the shared element transition to share sheet.
     * Note that once supplied, the action intent to share must be sent immediately after.
     */
    private Supplier<ShareTransition> getShareTransitionSupplier() {
    private Supplier<ActionTransition> getActionTransitionSupplier() {
        return () -> {
            ExitTransitionCallbacks cb = new ExitTransitionCallbacks() {
                @Override
@@ -668,7 +672,8 @@ public class ScreenshotController {
                }

                @Override
                public void onFinish() { }
                public void onFinish() {
                }
            };

            Pair<ActivityOptions, ExitTransitionCoordinator> transition =
@@ -677,7 +682,7 @@ public class ScreenshotController {
                                    ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME));
            transition.second.startExit();

            ShareTransition supply = new ShareTransition();
            ActionTransition supply = new ActionTransition();
            supply.bundle = transition.first.toBundle();
            supply.onCancelRunnable = () -> ActivityOptions.stopSharedElementAnimation(mWindow);
            return supply;
+53 −38
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ import android.widget.LinearLayout;

import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.shared.system.QuickStepContract;

import java.util.ArrayList;
@@ -105,7 +105,6 @@ public class ScreenshotView extends FrameLayout implements
    private static final long SCREENSHOT_DISMISS_Y_DURATION_MS = 350;
    private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183;
    private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
    private static final long SCREENSHOT_DISMISS_SHARE_OFFSET_MS = 300; // delay after share clicked
    private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
    private static final float ROUNDED_CORNER_RADIUS = .05f;
    private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
@@ -140,7 +139,7 @@ public class ScreenshotView extends FrameLayout implements
    private UiEventLogger mUiEventLogger;
    private ScreenshotViewCallback mCallbacks;
    private Animator mDismissAnimation;
    private boolean mIgnoreDismiss;
    private boolean mPendingSharedTransition;

    private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
    private PendingInteraction mPendingInteraction;
@@ -292,6 +291,10 @@ public class ScreenshotView extends FrameLayout implements
        requestFocus();
    }

    View getScreenshotPreview() {
        return mScreenshotPreview;
    }

    /**
     * Set up the logger and callback on dismissal.
     *
@@ -529,44 +532,22 @@ public class ScreenshotView extends FrameLayout implements
        });
        return animator;
    }
    protected View getScreenshotPreview() {
        return mScreenshotPreview;
    }

    void setChipIntents(ScreenshotController.SavedImageData imageData) {
        mShareChip.setOnClickListener(v -> {
            ShareTransition transition = imageData.shareTransition.get();
            try {
                mIgnoreDismiss = true;
                transition.shareAction.actionIntent.send();
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);

                // Ensures that we delay dismissing until transition has started.
                postDelayed(() -> {
                    mIgnoreDismiss = false;
                    animateDismissal();
                }, SCREENSHOT_DISMISS_SHARE_OFFSET_MS);
            } catch (PendingIntent.CanceledException e) {
                mIgnoreDismiss = false;
                if (transition.onCancelRunnable != null) {
                    transition.onCancelRunnable.run();
                }
                Log.e(TAG, "Share intent cancelled", e);
            }
            startSharedTransition(
                    imageData.shareTransition.get());
        });
        mEditChip.setPendingIntent(imageData.editAction.actionIntent,
                () -> {
        mEditChip.setOnClickListener(v -> {
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
                    animateDismissal();
            startSharedTransition(
                    imageData.editTransition.get());
        });
        mScreenshotPreview.setOnClickListener(v -> {
            try {
                imageData.editAction.actionIntent.send();
            } catch (PendingIntent.CanceledException e) {
                Log.e(TAG, "PendingIntent was cancelled", e);
            }
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
            animateDismissal();
            startSharedTransition(
                    imageData.editTransition.get());
        });

        if (mPendingInteraction != null) {
@@ -605,12 +586,16 @@ public class ScreenshotView extends FrameLayout implements
        return (mDismissAnimation != null && mDismissAnimation.isRunning());
    }

    boolean isPendingSharedTransition() {
        return mPendingSharedTransition;
    }

    void animateDismissal() {
        animateDismissal(createScreenshotDismissAnimation());
        animateDismissal(createScreenshotTranslateDismissAnimation());
    }

    private void animateDismissal(Animator dismissAnimation) {
        if (mIgnoreDismiss) {
        if (mPendingSharedTransition) {
            return;
        }
        if (DEBUG_WINDOW) {
@@ -665,6 +650,7 @@ public class ScreenshotView extends FrameLayout implements
        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
        // Clear any references to the bitmap
        mScreenshotPreview.setImageDrawable(null);
        mPendingSharedTransition = false;
        mActionsContainerBackground.setVisibility(View.GONE);
        mActionsContainer.setVisibility(View.GONE);
        mBackgroundProtection.setAlpha(0f);
@@ -692,7 +678,23 @@ public class ScreenshotView extends FrameLayout implements
        mScreenshotSelectorView.stop();
    }

    private AnimatorSet createScreenshotDismissAnimation() {
    private void startSharedTransition(ActionTransition transition) {
        try {
            mPendingSharedTransition = true;
            transition.action.actionIntent.send();

            // fade out non-preview UI
            createScreenshotFadeDismissAnimation().start();
        } catch (PendingIntent.CanceledException e) {
            mPendingSharedTransition = false;
            if (transition.onCancelRunnable != null) {
                transition.onCancelRunnable.run();
            }
            Log.e(TAG, "Intent cancelled", e);
        }
    }

    private AnimatorSet createScreenshotTranslateDismissAnimation() {
        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
        alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
        alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
@@ -719,6 +721,19 @@ public class ScreenshotView extends FrameLayout implements
        return animSet;
    }

    private ValueAnimator createScreenshotFadeDismissAnimation() {
        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
        alphaAnim.addUpdateListener(animation -> {
            float alpha = 1 - animation.getAnimatedFraction();
            mDismissButton.setAlpha(alpha);
            mActionsContainerBackground.setAlpha(alpha);
            mActionsContainer.setAlpha(alpha);
            mBackgroundProtection.setAlpha(alpha);
        });
        alphaAnim.setDuration(600);
        return alphaAnim;
    }

    /**
     * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
     */
+3 −1
Original line number Diff line number Diff line
@@ -72,9 +72,11 @@ public class TakeScreenshotService extends Service {
                if (DEBUG_DISMISS) {
                    Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
                }
                if (!mScreenshot.isPendingSharedTransition()) {
                    mScreenshot.dismissScreenshot(false);
                }
            }
        }
    };

    @Inject
Loading