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

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

Merge "Move dismiss animation into ScreenshotView"

parents 37bd0798 68e16b93
Loading
Loading
Loading
Loading
+27 −49
Original line number Diff line number Diff line
@@ -154,7 +154,6 @@ public class ScreenshotController {
    private SaveImageInBackgroundTask mSaveInBgTask;

    private Animator mScreenshotAnimation;
    private Animator mDismissAnimation;

    private Runnable mOnCompleteRunnable;
    private boolean mInDarkMode;
@@ -168,7 +167,6 @@ public class ScreenshotController {
                case MESSAGE_CORNER_TIMEOUT:
                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
                    ScreenshotController.this.dismissScreenshot(false);
                    mOnCompleteRunnable.run();
                    break;
                default:
                    break;
@@ -279,30 +277,22 @@ public class ScreenshotController {
                rect -> takeScreenshotInternal(finisher, rect));
    }

    boolean isDismissing() {
        return (mDismissAnimation != null && mDismissAnimation.isRunning());
    }

    /**
     * Clears current screenshot
     */
    void dismissScreenshot(boolean immediate) {
        Log.v(TAG, "clearing screenshot");
        mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
        mScreenshotView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
                mScreenshotView);
        if (!immediate) {
            mDismissAnimation = mScreenshotView.createScreenshotDismissAnimation();
            mDismissAnimation.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    clearScreenshot();
        // If we're already animating out, don't restart the animation
        // (but do obey an immediate dismissal)
        if (!immediate && mScreenshotView.isDismissing()) {
            Log.v(TAG, "Already dismissing, ignoring duplicate command");
            return;
        }
            });
            mDismissAnimation.start();
        Log.v(TAG, "Clearing screenshot");
        mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
        if (immediate) {
            resetScreenshotView();
        } else {
            clearScreenshot();
            mScreenshotView.animateDismissal();
        }
    }

@@ -373,6 +363,7 @@ public class ScreenshotController {
        // Inflate the screenshot layout
        mScreenshotView = (ScreenshotView)
                LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
        mScreenshotView.init(mUiEventLogger, this::resetScreenshotView);

        // TODO(159460485): Remove this when focus is handled properly in the system
        mScreenshotView.setOnTouchListener((v, event) -> {
@@ -438,10 +429,10 @@ public class ScreenshotController {

        if (mScreenshotView.isAttachedToWindow()) {
            // if we didn't already dismiss for another reason
            if (mDismissAnimation == null || !mDismissAnimation.isRunning()) {
            if (!mScreenshotView.isDismissing()) {
                mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
            }
            dismissScreenshot(true);
            mScreenshotView.reset();
        }

        mScreenBitmap = screenshot;
@@ -459,10 +450,6 @@ public class ScreenshotController {

        onConfigChanged(mContext.getResources().getConfiguration());

        if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
            mDismissAnimation.cancel();
        }

        // The window is focusable by default
        setWindowFocusable(true);

@@ -474,7 +461,8 @@ public class ScreenshotController {
            mScrollCaptureClient.request(DEFAULT_DISPLAY, (connection) ->
                    mScreenshotView.showScrollChip(() ->
                            runScrollCapture(connection,
                                    () -> dismissScreenshot(true))));
                                    () -> mScreenshotHandler.post(
                                            () -> dismissScreenshot(false)))));
        }
    }

@@ -519,6 +507,7 @@ public class ScreenshotController {
     */
    private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,
            boolean showFlash) {
        mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
        mScreenshotHandler.post(() -> {
            if (!mScreenshotView.isAttachedToWindow()) {
                mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
@@ -531,8 +520,7 @@ public class ScreenshotController {
                        mScreenshotView);

                mScreenshotAnimation =
                        mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash,
                                this::onElementTapped);
                        mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash);

                saveScreenshotInWorkerThread(finisher,
                        new ScreenshotController.ActionsReadyListener() {
@@ -551,6 +539,14 @@ public class ScreenshotController {
        });
    }

    private void resetScreenshotView() {
        if (mScreenshotView.isAttachedToWindow()) {
            mWindowManager.removeView(mScreenshotView);
        }
        mScreenshotView.reset();
        mOnCompleteRunnable.run();
    }

    /**
     * Creates a new worker thread and saves the screenshot to the media store.
     */
@@ -590,7 +586,6 @@ public class ScreenshotController {
                SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
                AccessibilityManager.FLAG_CONTENT_CONTROLS);

        mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
        mScreenshotHandler.sendMessageDelayed(
                mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
                timeoutMs);
@@ -602,24 +597,16 @@ public class ScreenshotController {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            super.onAnimationEnd(animation);
                            mScreenshotView.setChipIntents(
                                    imageData, event -> onElementTapped(event));
                            mScreenshotView.setChipIntents(imageData);
                        }
                    });
                } else {
                    mScreenshotView.setChipIntents(
                            imageData, this::onElementTapped);
                    mScreenshotView.setChipIntents(imageData);
                }
            });
        }
    }

    private void onElementTapped(ScreenshotEvent event) {
        mUiEventLogger.log(event);
        dismissScreenshot(false);
        mOnCompleteRunnable.run();
    }

    /**
     * Logs success/failure of the screenshot saving task, and shows an error if it failed.
     */
@@ -633,20 +620,11 @@ public class ScreenshotController {
        }
    }

    private void clearScreenshot() {
        if (mScreenshotView.isAttachedToWindow()) {
            mWindowManager.removeView(mScreenshotView);
        }

        mScreenshotView.reset();
    }

    private boolean isUserSetupComplete() {
        return Settings.Secure.getInt(mContext.getContentResolver(),
                SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
    }


    /**
     * Updates the window focusability.  If the window is already showing, then it updates the
     * window immediately, otherwise the layout params will be applied when the window is next
+91 −35
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.shared.system.QuickStepContract;

@@ -115,6 +116,10 @@ public class ScreenshotView extends FrameLayout implements
    private ScreenshotActionChip mEditChip;
    private ScreenshotActionChip mScrollChip;

    private UiEventLogger mUiEventLogger;
    private Runnable mOnDismissRunnable;
    private Animator mDismissAnimation;

    private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
    private PendingInteraction mPendingInteraction;

@@ -248,6 +253,17 @@ public class ScreenshotView extends FrameLayout implements
        requestFocus();
    }

    /**
     * Set up the logger and callback on dismissal.
     *
     * Note: must be called before any other (non-constructor) method or null pointer exceptions
     * may occur.
     */
    void init(UiEventLogger uiEventLogger, Runnable onDismissRunnable) {
        mUiEventLogger = uiEventLogger;
        mOnDismissRunnable = onDismissRunnable;
    }

    void takePartialScreenshot(Consumer<Rect> onPartialScreenshotSelected) {
        mScreenshotSelectorView.setOnScreenshotSelected(onPartialScreenshotSelected);
        mScreenshotSelectorView.setVisibility(View.VISIBLE);
@@ -260,8 +276,7 @@ public class ScreenshotView extends FrameLayout implements
        mScreenshotPreview.setVisibility(View.INVISIBLE);
    }

    AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash,
            Consumer<ScreenshotEvent> onElementTapped) {
    AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
        mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        mScreenshotPreview.buildLayer();

@@ -362,8 +377,10 @@ public class ScreenshotView extends FrameLayout implements
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mDismissButton.setOnClickListener(view ->
                        onElementTapped.accept(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL));
                mDismissButton.setOnClickListener(view -> {
                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
                    animateDismissal();
                });
                mDismissButton.setAlpha(1);
                float dismissOffset = mDismissButton.getWidth() / 2f;
                float finalDismissX = mDirectionLTR
@@ -460,19 +477,25 @@ public class ScreenshotView extends FrameLayout implements
        return animator;
    }

    void setChipIntents(ScreenshotController.SavedImageData imageData,
            Consumer<ScreenshotEvent> onElementTapped) {
    void setChipIntents(ScreenshotController.SavedImageData imageData) {
        mShareChip.setPendingIntent(imageData.shareAction.actionIntent,
                () -> onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED));
                () -> {
                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
                    animateDismissal();
                });
        mEditChip.setPendingIntent(imageData.editAction.actionIntent,
                () -> onElementTapped.accept(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED));
                () -> {
                    mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
                    animateDismissal();
                });
        mScreenshotPreview.setOnClickListener(v -> {
            try {
                imageData.editAction.actionIntent.send();
            } catch (PendingIntent.CanceledException e) {
                Log.e(TAG, "Intent cancelled", e);
            }
            onElementTapped.accept(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
            animateDismissal();
        });

        if (mPendingInteraction != null) {
@@ -496,43 +519,49 @@ public class ScreenshotView extends FrameLayout implements
                actionChip.setText(smartAction.title);
                actionChip.setIcon(smartAction.getIcon(), false);
                actionChip.setPendingIntent(smartAction.actionIntent,
                        () -> onElementTapped.accept(
                                ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED));
                        () -> {
                            mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
                            animateDismissal();
                        });
                mActionsView.addView(actionChip);
                mSmartChips.add(actionChip);
            }
        }
    }

    boolean isDismissing() {
        return (mDismissAnimation != null && mDismissAnimation.isRunning());
    }

    AnimatorSet createScreenshotDismissAnimation() {
        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
        alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
        alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
        alphaAnim.addUpdateListener(animation -> {
            setAlpha(1 - animation.getAnimatedFraction());
        });

        ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
        yAnim.setInterpolator(mAccelerateInterpolator);
        yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
        float screenshotStartY = mScreenshotPreview.getTranslationY();
        float dismissStartY = mDismissButton.getTranslationY();
        yAnim.addUpdateListener(animation -> {
            float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
            mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
            mDismissButton.setTranslationY(dismissStartY + yDelta);
            mActionsContainer.setTranslationY(yDelta);
            mActionsContainerBackground.setTranslationY(yDelta);
        });
    void animateDismissal() {
        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
        mDismissAnimation = createScreenshotDismissAnimation();
        mDismissAnimation.addListener(new AnimatorListenerAdapter() {
            private boolean mCancelled = false;

        AnimatorSet animSet = new AnimatorSet();
        animSet.play(yAnim).with(alphaAnim);
            @Override
            public void onAnimationCancel(Animator animation) {
                super.onAnimationCancel(animation);
                mCancelled = true;
            }

        return animSet;
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (!mCancelled) {
                    mOnDismissRunnable.run();
                }
            }
        });
        mDismissAnimation.start();
    }

    void reset() {
        if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
            mDismissAnimation.cancel();
        }
        // Make sure we clean up the view tree observer
        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
        // Clear any references to the bitmap
        mScreenshotPreview.setImageDrawable(null);
        mActionsContainerBackground.setVisibility(View.GONE);
@@ -561,6 +590,33 @@ public class ScreenshotView extends FrameLayout implements
        mScreenshotSelectorView.stop();
    }

    private AnimatorSet createScreenshotDismissAnimation() {
        ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
        alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
        alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
        alphaAnim.addUpdateListener(animation -> {
            setAlpha(1 - animation.getAnimatedFraction());
        });

        ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
        yAnim.setInterpolator(mAccelerateInterpolator);
        yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
        float screenshotStartY = mScreenshotPreview.getTranslationY();
        float dismissStartY = mDismissButton.getTranslationY();
        yAnim.addUpdateListener(animation -> {
            float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
            mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
            mDismissButton.setTranslationY(dismissStartY + yDelta);
            mActionsContainer.setTranslationY(yDelta);
            mActionsContainerBackground.setTranslationY(yDelta);
        });

        AnimatorSet animSet = new AnimatorSet();
        animSet.play(yAnim).with(alphaAnim);

        return animSet;
    }

    /**
     * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
     */
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ public class TakeScreenshotService extends Service {

    @Override
    public boolean onUnbind(Intent intent) {
        if (mScreenshot != null && !mScreenshot.isDismissing()) {
        if (mScreenshot != null) {
            mScreenshot.dismissScreenshot(true);
        }
        unregisterReceiver(mBroadcastReceiver);