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

Commit 1de4c3f4 authored by Winson Chung's avatar Winson Chung Committed by Mady Mellor
Browse files

PIP dismiss updates

* orders the target below the PIP surface
* adds scale relative to the dismiss target size when PIP is in
  the target

Test: manual - get a pip, drag it to dismiss => it appears on top of
               the circle and then animates away with it
             - get a pip, make it larger with 2 finger gesture,
               drag it to dismiss => it appears on top of the circle
               and fits nicely in the circle bounds
Bug: 183657564
Change-Id: I5c096c2b5f41a667df37b4c6668c4862a212c7e2
parent 9254393a
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -379,6 +379,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
        }
        }
    }
    }


    public SurfaceControl getSurfaceControl() {
        return mLeash;
    }

    private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
    private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
            ActivityInfo activityInfo) {
            ActivityInfo activityInfo) {
        mPipBoundsState.setBoundsStateForEntry(componentName,
        mPipBoundsState.setBoundsStateForEntry(componentName,
+34 −2
Original line number Original line Diff line number Diff line
@@ -26,8 +26,10 @@ import android.graphics.Rect;
import android.graphics.drawable.TransitionDrawable;
import android.graphics.drawable.TransitionDrawable;
import android.view.Gravity;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.FrameLayout;


@@ -47,7 +49,7 @@ import kotlin.Unit;
/**
/**
 * Handler of all Magnetized Object related code for PiP.
 * Handler of all Magnetized Object related code for PiP.
 */
 */
public class PipDismissTargetHandler {
public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListener {


    /* The multiplier to apply scale the target size by when applying the magnetic field radius */
    /* The multiplier to apply scale the target size by when applying the magnetic field radius */
    private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
    private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
@@ -92,6 +94,9 @@ public class PipDismissTargetHandler {
    private int mDismissAreaHeight;
    private int mDismissAreaHeight;
    private float mMagneticFieldRadiusPercent = 1f;
    private float mMagneticFieldRadiusPercent = 1f;


    private SurfaceControl mTaskLeash;
    private boolean mHasDismissTargetSurface;

    private final Context mContext;
    private final Context mContext;
    private final PipMotionHelper mMotionHelper;
    private final PipMotionHelper mMotionHelper;
    private final PipUiEventLogger mPipUiEventLogger;
    private final PipUiEventLogger mPipUiEventLogger;
@@ -167,6 +172,14 @@ public class PipDismissTargetHandler {
        mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
        mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView);
    }
    }


    @Override
    public boolean onPreDraw() {
        mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
        mHasDismissTargetSurface = true;
        updateDismissTargetLayer();
        return true;
    }

    /**
    /**
     * Potentially start consuming future motion events if PiP is currently near the magnetized
     * Potentially start consuming future motion events if PiP is currently near the magnetized
     * object.
     * object.
@@ -207,12 +220,31 @@ public class PipDismissTargetHandler {
                        * MAGNETIC_FIELD_RADIUS_MULTIPLIER));
                        * MAGNETIC_FIELD_RADIUS_MULTIPLIER));
    }
    }


    public void setTaskLeash(SurfaceControl taskLeash) {
        mTaskLeash = taskLeash;
    }

    private void updateDismissTargetLayer() {
        if (!mHasDismissTargetSurface || mTaskLeash == null) {
            // No dismiss target surface, can just return
            return;
        }

        // Put the dismiss target behind the task
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        t.setRelativeLayer(mTargetViewContainer.getViewRootImpl().getSurfaceControl(),
                mTaskLeash, -1);
        t.apply();
    }

    /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
    /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */
    public void createOrUpdateDismissTarget() {
    public void createOrUpdateDismissTarget() {
        if (!mTargetViewContainer.isAttachedToWindow()) {
        if (!mTargetViewContainer.isAttachedToWindow()) {
            mMagneticTargetAnimator.cancel();
            mMagneticTargetAnimator.cancel();


            mTargetViewContainer.setVisibility(View.INVISIBLE);
            mTargetViewContainer.setVisibility(View.INVISIBLE);
            mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
            mHasDismissTargetSurface = false;


            try {
            try {
                mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams());
                mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams());
@@ -259,9 +291,9 @@ public class PipDismissTargetHandler {
        createOrUpdateDismissTarget();
        createOrUpdateDismissTarget();


        if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
        if (mTargetViewContainer.getVisibility() != View.VISIBLE) {

            mTargetView.setTranslationY(mTargetViewContainer.getHeight());
            mTargetView.setTranslationY(mTargetViewContainer.getHeight());
            mTargetViewContainer.setVisibility(View.VISIBLE);
            mTargetViewContainer.setVisibility(View.VISIBLE);
            mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);


            // Cancel in case we were in the middle of animating it out.
            // Cancel in case we were in the middle of animating it out.
            mMagneticTargetAnimator.cancel();
            mMagneticTargetAnimator.cancel();
+13 −2
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import android.view.Choreographer;
import androidx.dynamicanimation.animation.AnimationHandler;
import androidx.dynamicanimation.animation.AnimationHandler;
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;


import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -71,6 +72,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,


    /** Friction to use for PIP when it moves via physics fling animations. */
    /** Friction to use for PIP when it moves via physics fling animations. */
    private static final float DEFAULT_FRICTION = 1.9f;
    private static final float DEFAULT_FRICTION = 1.9f;
    /** How much of the dismiss circle size to use when scaling down PIP. **/
    private static final float DISMISS_CIRCLE_PERCENT = 0.85f;


    private final Context mContext;
    private final Context mContext;
    private final PipTaskOrganizer mPipTaskOrganizer;
    private final PipTaskOrganizer mPipTaskOrganizer;
@@ -296,9 +299,17 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
            boolean flung, Function0<Unit> after) {
            boolean flung, Function0<Unit> after) {
        final PointF targetCenter = target.getCenterOnScreen();
        final PointF targetCenter = target.getCenterOnScreen();


        final float desiredWidth = getBounds().width() / 2;
        // PIP should fit in the circle
        final float desiredHeight = getBounds().height() / 2;
        final float dismissCircleSize = mContext.getResources().getDimensionPixelSize(
                R.dimen.dismiss_circle_size);


        final float width = getBounds().width();
        final float height = getBounds().height();
        final float ratio = width / height;

        // Width should be a little smaller than the circle size.
        final float desiredWidth = dismissCircleSize * DISMISS_CIRCLE_PERCENT;
        final float desiredHeight = desiredWidth / ratio;
        final float destinationX = targetCenter.x - (desiredWidth / 2f);
        final float destinationX = targetCenter.x - (desiredWidth / 2f);
        final float destinationY = targetCenter.y - (desiredHeight / 2f);
        final float destinationY = targetCenter.y - (desiredHeight / 2f);


+4 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@ public class PipTouchHandler {
    private final @NonNull PipBoundsState mPipBoundsState;
    private final @NonNull PipBoundsState mPipBoundsState;
    private final PipUiEventLogger mPipUiEventLogger;
    private final PipUiEventLogger mPipUiEventLogger;
    private final PipDismissTargetHandler mPipDismissTargetHandler;
    private final PipDismissTargetHandler mPipDismissTargetHandler;
    private final PipTaskOrganizer mPipTaskOrganizer;
    private final ShellExecutor mMainExecutor;
    private final ShellExecutor mMainExecutor;


    private PipResizeGestureHandler mPipResizeGestureHandler;
    private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -173,6 +174,7 @@ public class PipTouchHandler {
        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
        mPipBoundsAlgorithm = pipBoundsAlgorithm;
        mPipBoundsAlgorithm = pipBoundsAlgorithm;
        mPipBoundsState = pipBoundsState;
        mPipBoundsState = pipBoundsState;
        mPipTaskOrganizer = pipTaskOrganizer;
        mMenuController = menuController;
        mMenuController = menuController;
        mPipUiEventLogger = pipUiEventLogger;
        mPipUiEventLogger = pipUiEventLogger;
        mFloatingContentCoordinator = floatingContentCoordinator;
        mFloatingContentCoordinator = floatingContentCoordinator;
@@ -799,6 +801,7 @@ public class PipTouchHandler {
            mMovementWithinDismiss = touchState.getDownTouchPosition().y
            mMovementWithinDismiss = touchState.getDownTouchPosition().y
                    >= mPipBoundsState.getMovementBounds().bottom;
                    >= mPipBoundsState.getMovementBounds().bottom;
            mMotionHelper.setSpringingToTouch(false);
            mMotionHelper.setSpringingToTouch(false);
            mPipDismissTargetHandler.setTaskLeash(mPipTaskOrganizer.getSurfaceControl());


            // If the menu is still visible then just poke the menu
            // If the menu is still visible then just poke the menu
            // so that it will timeout after the user stops touching it
            // so that it will timeout after the user stops touching it
@@ -847,6 +850,7 @@ public class PipTouchHandler {
        @Override
        @Override
        public boolean onUp(PipTouchState touchState) {
        public boolean onUp(PipTouchState touchState) {
            mPipDismissTargetHandler.hideDismissTargetMaybe();
            mPipDismissTargetHandler.hideDismissTargetMaybe();
            mPipDismissTargetHandler.setTaskLeash(null);


            if (!touchState.isUserInteracting()) {
            if (!touchState.isUserInteracting()) {
                return false;
                return false;