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
This commit is contained in:
Winson Chung
2021-06-02 17:24:15 -07:00
committed by Mady Mellor
parent 9254393aa5
commit 1de4c3f418
4 changed files with 55 additions and 4 deletions

View File

@@ -379,6 +379,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
public SurfaceControl getSurfaceControl() {
return mLeash;
}
private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
ActivityInfo activityInfo) {
mPipBoundsState.setBoundsStateForEntry(componentName,

View File

@@ -26,8 +26,10 @@ import android.graphics.Rect;
import android.graphics.drawable.TransitionDrawable;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -47,7 +49,7 @@ import kotlin.Unit;
/**
* 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 */
private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
@@ -92,6 +94,9 @@ public class PipDismissTargetHandler {
private int mDismissAreaHeight;
private float mMagneticFieldRadiusPercent = 1f;
private SurfaceControl mTaskLeash;
private boolean mHasDismissTargetSurface;
private final Context mContext;
private final PipMotionHelper mMotionHelper;
private final PipUiEventLogger mPipUiEventLogger;
@@ -167,6 +172,14 @@ public class PipDismissTargetHandler {
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
* object.
@@ -207,12 +220,31 @@ public class PipDismissTargetHandler {
* 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. */
public void createOrUpdateDismissTarget() {
if (!mTargetViewContainer.isAttachedToWindow()) {
mMagneticTargetAnimator.cancel();
mTargetViewContainer.setVisibility(View.INVISIBLE);
mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
mHasDismissTargetSurface = false;
try {
mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams());
@@ -259,9 +291,9 @@ public class PipDismissTargetHandler {
createOrUpdateDismissTarget();
if (mTargetViewContainer.getVisibility() != View.VISIBLE) {
mTargetView.setTranslationY(mTargetViewContainer.getHeight());
mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.getViewTreeObserver().addOnPreDrawListener(this);
// Cancel in case we were in the middle of animating it out.
mMagneticTargetAnimator.cancel();

View File

@@ -40,6 +40,7 @@ import android.view.Choreographer;
import androidx.dynamicanimation.animation.AnimationHandler;
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.PhysicsAnimator;
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. */
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 PipTaskOrganizer mPipTaskOrganizer;
@@ -296,9 +299,17 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
boolean flung, Function0<Unit> after) {
final PointF targetCenter = target.getCenterOnScreen();
final float desiredWidth = getBounds().width() / 2;
final float desiredHeight = getBounds().height() / 2;
// PIP should fit in the circle
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 destinationY = targetCenter.y - (desiredHeight / 2f);

View File

@@ -75,6 +75,7 @@ public class PipTouchHandler {
private final @NonNull PipBoundsState mPipBoundsState;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
private final PipTaskOrganizer mPipTaskOrganizer;
private final ShellExecutor mMainExecutor;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -173,6 +174,7 @@ public class PipTouchHandler {
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
mPipTaskOrganizer = pipTaskOrganizer;
mMenuController = menuController;
mPipUiEventLogger = pipUiEventLogger;
mFloatingContentCoordinator = floatingContentCoordinator;
@@ -799,6 +801,7 @@ public class PipTouchHandler {
mMovementWithinDismiss = touchState.getDownTouchPosition().y
>= mPipBoundsState.getMovementBounds().bottom;
mMotionHelper.setSpringingToTouch(false);
mPipDismissTargetHandler.setTaskLeash(mPipTaskOrganizer.getSurfaceControl());
// If the menu is still visible then just poke the menu
// so that it will timeout after the user stops touching it
@@ -847,6 +850,7 @@ public class PipTouchHandler {
@Override
public boolean onUp(PipTouchState touchState) {
mPipDismissTargetHandler.hideDismissTargetMaybe();
mPipDismissTargetHandler.setTaskLeash(null);
if (!touchState.isUserInteracting()) {
return false;