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:
committed by
Mady Mellor
parent
9254393aa5
commit
1de4c3f418
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user