diff options
5 files changed, 312 insertions, 305 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java new file mode 100644 index 000000000000..bebe5f965251 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip.phone; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.TransitionDrawable; +import android.os.Handler; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringForce; + +import com.android.wm.shell.R; +import com.android.wm.shell.animation.PhysicsAnimator; +import com.android.wm.shell.common.DismissCircleView; +import com.android.wm.shell.common.magnetictarget.MagnetizedObject; +import com.android.wm.shell.pip.PipUiEventLogger; + +import kotlin.Unit; + +/** + * Handler of all Magnetized Object related code for PiP. + */ +public class PipDismissTargetHandler { + + /* 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; + + /** Duration of the dismiss scrim fading in/out. */ + private static final int DISMISS_TRANSITION_DURATION_MS = 200; + + /** + * MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move + * PIP. + */ + private final MagnetizedObject<Rect> mMagnetizedPip; + + /** + * Container for the dismiss circle, so that it can be animated within the container via + * translation rather than within the WindowManager via slow layout animations. + */ + private final ViewGroup mTargetViewContainer; + + /** Circle view used to render the dismiss target. */ + private final DismissCircleView mTargetView; + + /** + * MagneticTarget instance wrapping the target view and allowing us to set its magnetic radius. + */ + private final MagnetizedObject.MagneticTarget mMagneticTarget; + + /** PhysicsAnimator instance for animating the dismiss target in/out. */ + private final PhysicsAnimator<View> mMagneticTargetAnimator; + + /** Default configuration to use for springing the dismiss target in/out. */ + private final PhysicsAnimator.SpringConfig mTargetSpringConfig = + new PhysicsAnimator.SpringConfig( + SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + + /** + * Runnable that can be posted delayed to show the target. This needs to be saved as a member + * variable so we can pass it to removeCallbacks. + */ + private Runnable mShowTargetAction = this::showDismissTargetMaybe; + + // Allow dragging the PIP to a location to close it + private final boolean mEnableDismissDragToEdge; + + private int mDismissAreaHeight; + + private final Context mContext; + private final PipMotionHelper mMotionHelper; + private final PipUiEventLogger mPipUiEventLogger; + private final WindowManager mWindowManager; + private final Handler mHandler; + + public PipDismissTargetHandler(Context context, PipUiEventLogger pipUiEventLogger, + PipMotionHelper motionHelper, Handler handler) { + mContext = context; + mPipUiEventLogger = pipUiEventLogger; + mMotionHelper = motionHelper; + mHandler = handler; + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + + Resources res = context.getResources(); + mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge); + mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height); + + mTargetView = new DismissCircleView(context); + mTargetViewContainer = new FrameLayout(context); + mTargetViewContainer.setBackgroundDrawable( + context.getDrawable(R.drawable.floating_dismiss_gradient_transition)); + mTargetViewContainer.setClipChildren(false); + mTargetViewContainer.addView(mTargetView); + + mMagnetizedPip = mMotionHelper.getMagnetizedPip(); + mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0); + updateMagneticTargetSize(); + + mMagnetizedPip.setAnimateStuckToTarget( + (target, velX, velY, flung, after) -> { + if (mEnableDismissDragToEdge) { + mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after); + } + return Unit.INSTANCE; + }); + mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { + @Override + public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) { + // Show the dismiss target, in case the initial touch event occurred within the + // magnetic field radius. + if (mEnableDismissDragToEdge) { + showDismissTargetMaybe(); + } + } + + @Override + public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target, + float velX, float velY, boolean wasFlungOut) { + if (wasFlungOut) { + mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */); + hideDismissTargetMaybe(); + } else { + mMotionHelper.setSpringingToTouch(true); + } + } + + @Override + public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { + mMotionHelper.notifyDismissalPending(); + + handler.post(() -> { + mMotionHelper.animateDismiss(); + hideDismissTargetMaybe(); + }); + + mPipUiEventLogger.log( + PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE); + } + }); + + mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView); + } + + /** + * Potentially start consuming future motion events if PiP is currently near the magnetized + * object. + */ + public boolean maybeConsumeMotionEvent(MotionEvent ev) { + return mMagnetizedPip.maybeConsumeMotionEvent(ev); + } + + /** + * Update the magnet size. + */ + public void updateMagneticTargetSize() { + if (mTargetView == null) { + return; + } + + final Resources res = mContext.getResources(); + final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); + mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height); + final FrameLayout.LayoutParams newParams = + new FrameLayout.LayoutParams(targetSize, targetSize); + newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + newParams.bottomMargin = mContext.getResources().getDimensionPixelSize( + R.dimen.floating_dismiss_bottom_margin); + mTargetView.setLayoutParams(newParams); + + // Set the magnetic field radius equal to the target size from the center of the target + mMagneticTarget.setMagneticFieldRadiusPx( + (int) (targetSize * MAGNETIC_FIELD_RADIUS_MULTIPLIER)); + } + + /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */ + public void createOrUpdateDismissTarget() { + if (!mTargetViewContainer.isAttachedToWindow()) { + mHandler.removeCallbacks(mShowTargetAction); + mMagneticTargetAnimator.cancel(); + + mTargetViewContainer.setVisibility(View.INVISIBLE); + + try { + mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams()); + } catch (IllegalStateException e) { + // This shouldn't happen, but if the target is already added, just update its layout + // params. + mWindowManager.updateViewLayout( + mTargetViewContainer, getDismissTargetLayoutParams()); + } + } else { + mWindowManager.updateViewLayout(mTargetViewContainer, getDismissTargetLayoutParams()); + } + } + + /** Returns layout params for the dismiss target, using the latest display metrics. */ + private WindowManager.LayoutParams getDismissTargetLayoutParams() { + final Point windowSize = new Point(); + mWindowManager.getDefaultDisplay().getRealSize(windowSize); + + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + mDismissAreaHeight, + 0, windowSize.y - mDismissAreaHeight, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + + lp.setTitle("pip-dismiss-overlay"); + lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + lp.setFitInsetsTypes(0 /* types */); + + return lp; + } + + /** Makes the dismiss target visible and animates it in, if it isn't already visible. */ + public void showDismissTargetMaybe() { + if (!mEnableDismissDragToEdge) { + return; + } + + createOrUpdateDismissTarget(); + + if (mTargetViewContainer.getVisibility() != View.VISIBLE) { + + mTargetView.setTranslationY(mTargetViewContainer.getHeight()); + mTargetViewContainer.setVisibility(View.VISIBLE); + + // Cancel in case we were in the middle of animating it out. + mMagneticTargetAnimator.cancel(); + mMagneticTargetAnimator + .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig) + .start(); + + ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition( + DISMISS_TRANSITION_DURATION_MS); + } + } + + /** Animates the magnetic dismiss target out and then sets it to GONE. */ + public void hideDismissTargetMaybe() { + if (!mEnableDismissDragToEdge) { + return; + } + + mHandler.removeCallbacks(mShowTargetAction); + mMagneticTargetAnimator + .spring(DynamicAnimation.TRANSLATION_Y, + mTargetViewContainer.getHeight(), + mTargetSpringConfig) + .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE)) + .start(); + + ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition( + DISMISS_TRANSITION_DURATION_MS); + } + + /** + * Removes the dismiss target and cancels any pending callbacks to show it. + */ + public void cleanUpDismissTarget() { + mHandler.removeCallbacks(mShowTargetAction); + + if (mTargetViewContainer.isAttachedToWindow()) { + mWindowManager.removeViewImmediate(mTargetViewContainer); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java index c53803a7f8cc..cd47d55da7f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java @@ -156,20 +156,6 @@ public class PipMenuActivityController { } /** - * Updates the appearance of the menu and scrim on top of the PiP while dismissing. - */ - public void setDismissFraction(float fraction) { - final boolean isMenuVisible = isMenuVisible(); - if (DEBUG) { - Log.d(TAG, "setDismissFraction() isMenuVisible=" + isMenuVisible - + " fraction=" + fraction); - } - if (isMenuVisible) { - mPipMenuView.updateDismissFraction(fraction); - } - } - - /** * Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu * upon PiP window transition is finished. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index 24e49f8d9821..51951409f76c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -429,25 +429,6 @@ public class PipMenuView extends FrameLayout { } } - void updateDismissFraction(float fraction) { - int alpha; - final float menuAlpha = 1 - fraction; - if (mMenuState == MENU_STATE_FULL) { - mMenuContainer.setAlpha(menuAlpha); - mSettingsButton.setAlpha(menuAlpha); - mDismissButton.setAlpha(menuAlpha); - final float interpolatedAlpha = - MENU_BACKGROUND_ALPHA * menuAlpha + DISMISS_BACKGROUND_ALPHA * fraction; - alpha = (int) (interpolatedAlpha * 255); - } else { - if (mMenuState == MENU_STATE_CLOSE) { - mDismissButton.setAlpha(menuAlpha); - } - alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255); - } - mBackgroundDrawable.setAlpha(alpha); - } - private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) { mMenuState = menuState; mController.onMenuStateChanged(menuState, resize, callback); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java index cc86cf97104b..fe1d44c72845 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java @@ -385,23 +385,20 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * Flings the PiP to the closest snap target. */ void flingToSnapTarget( - float velocityX, float velocityY, - @Nullable Runnable updateAction, @Nullable Runnable endAction) { - movetoTarget(velocityX, velocityY, updateAction, endAction, false /* isStash */); + float velocityX, float velocityY, @Nullable Runnable endAction) { + movetoTarget(velocityX, velocityY, endAction, false /* isStash */); } /** * Stash PiP to the closest edge. */ void stashToEdge( - float velocityX, float velocityY, - @Nullable Runnable updateAction, @Nullable Runnable endAction) { - movetoTarget(velocityX, velocityY, updateAction, endAction, true /* isStash */); + float velocityX, float velocityY, @Nullable Runnable endAction) { + movetoTarget(velocityX, velocityY, endAction, true /* isStash */); } private void movetoTarget( - float velocityX, float velocityY, - @Nullable Runnable updateAction, @Nullable Runnable endAction, boolean isStash) { + float velocityX, float velocityY, @Nullable Runnable endAction, boolean isStash) { // If we're flinging to a snap target now, we're not springing to catch up to the touch // location now. mSpringingToTouch = false; @@ -416,11 +413,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig) .withEndActions(endAction); - if (updateAction != null) { - mTemporaryBoundsPhysicsAnimator.addUpdateListener( - (target, values) -> updateAction.run()); - } - final float offset = ((float) mBounds.width()) * (1.0f - STASH_RATIO); final float leftEdge = isStash ? mMovementBounds.left - offset : mMovementBounds.left; final float rightEdge = isStash ? mMovementBounds.right + offset : mMovementBounds.right; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index 6b3177225a35..07beb43d4faa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -26,40 +26,26 @@ import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; -import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.TransitionDrawable; import android.os.Handler; import android.os.RemoteException; import android.provider.DeviceConfig; import android.util.Log; import android.util.Size; -import android.view.Gravity; import android.view.IPinnedStackController; import android.view.InputEvent; import android.view.MotionEvent; -import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.R; -import com.android.wm.shell.animation.PhysicsAnimator; -import com.android.wm.shell.common.DismissCircleView; import com.android.wm.shell.common.FloatingContentCoordinator; -import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipTaskOrganizer; @@ -67,8 +53,6 @@ import com.android.wm.shell.pip.PipUiEventLogger; import java.io.PrintWriter; -import kotlin.Unit; - /** * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding * the PIP. @@ -82,14 +66,12 @@ public class PipTouchHandler { /* 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; - // Allow dragging the PIP to a location to close it - private final boolean mEnableDismissDragToEdge; // Allow PIP to resize to a slightly bigger state upon touch private final boolean mEnableResize; private final Context mContext; - private final WindowManager mWindowManager; private final PipBoundsHandler mPipBoundsHandler; private final PipUiEventLogger mPipUiEventLogger; + private final PipDismissTargetHandler mPipDismissTargetHandler; private PipResizeGestureHandler mPipResizeGestureHandler; private IPinnedStackController mPinnedStackController; @@ -105,34 +87,6 @@ public class PipTouchHandler { */ private boolean mEnableStash = false; - /** - * MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move - * PIP. - */ - private MagnetizedObject<Rect> mMagnetizedPip; - - /** - * Container for the dismiss circle, so that it can be animated within the container via - * translation rather than within the WindowManager via slow layout animations. - */ - private ViewGroup mTargetViewContainer; - - /** Circle view used to render the dismiss target. */ - private DismissCircleView mTargetView; - - /** - * MagneticTarget instance wrapping the target view and allowing us to set its magnetic radius. - */ - private MagnetizedObject.MagneticTarget mMagneticTarget; - - /** PhysicsAnimator instance for animating the dismiss target in/out. */ - private PhysicsAnimator<View> mMagneticTargetAnimator; - - /** Default configuration to use for springing the dismiss target in/out. */ - private final PhysicsAnimator.SpringConfig mTargetSpringConfig = - new PhysicsAnimator.SpringConfig( - SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); - // The current movement bounds private Rect mMovementBounds = new Rect(); @@ -150,12 +104,6 @@ public class PipTouchHandler { private int mDeferResizeToNormalBoundsUntilRotation = -1; private int mDisplayRotation; - /** - * Runnable that can be posted delayed to show the target. This needs to be saved as a member - * variable so we can pass it to removeCallbacks. - */ - private Runnable mShowTargetAction = this::showDismissTargetMaybe; - private Handler mHandler = new Handler(); // Behaviour states @@ -163,7 +111,6 @@ public class PipTouchHandler { private boolean mIsImeShowing; private int mImeHeight; private int mImeOffset; - private int mDismissAreaHeight; private boolean mIsShelfShowing; private int mShelfHeight; private int mMovementBoundsExtraOffsets; @@ -221,7 +168,6 @@ public class PipTouchHandler { mContext = context; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); mPipBoundsHandler = pipBoundsHandler; - mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mMenuController = menuController; mMenuController.addListener(new PipMenuListener()); mGesture = new DefaultPipTouchGesture(); @@ -231,13 +177,14 @@ public class PipTouchHandler { new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper, pipTaskOrganizer, this::getMovementBounds, this::updateMovementBounds, pipUiEventLogger, menuController); + mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger, + mMotionHelper, mHandler); mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler, () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(), true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()), menuController::hideMenu); Resources res = context.getResources(); - mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge); mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu); reloadResources(); @@ -248,61 +195,6 @@ public class PipTouchHandler { mPipUiEventLogger = pipUiEventLogger; - mTargetView = new DismissCircleView(context); - mTargetViewContainer = new FrameLayout(context); - mTargetViewContainer.setBackgroundDrawable( - context.getDrawable(R.drawable.floating_dismiss_gradient_transition)); - mTargetViewContainer.setClipChildren(false); - mTargetViewContainer.addView(mTargetView); - - mMagnetizedPip = mMotionHelper.getMagnetizedPip(); - mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0); - updateMagneticTargetSize(); - - mMagnetizedPip.setAnimateStuckToTarget( - (target, velX, velY, flung, after) -> { - if (mEnableDismissDragToEdge) { - mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after); - } - return Unit.INSTANCE; - }); - mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { - @Override - public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) { - // Show the dismiss target, in case the initial touch event occurred within the - // magnetic field radius. - if (mEnableDismissDragToEdge) { - showDismissTargetMaybe(); - } - } - - @Override - public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target, - float velX, float velY, boolean wasFlungOut) { - if (wasFlungOut) { - mMotionHelper.flingToSnapTarget(velX, velY, null, null); - hideDismissTarget(); - } else { - mMotionHelper.setSpringingToTouch(true); - } - } - - @Override - public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { - mMotionHelper.notifyDismissalPending(); - - mHandler.post(() -> { - mMotionHelper.animateDismiss(); - hideDismissTarget(); - }); - - mPipUiEventLogger.log( - PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE); - } - }); - - mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView); - mEnableStash = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, PIP_STASHING, @@ -323,27 +215,7 @@ public class PipTouchHandler { mExpandedShortestEdgeSize = res.getDimensionPixelSize( R.dimen.pip_expanded_shortest_edge_size); mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset); - mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height); - updateMagneticTargetSize(); - } - - private void updateMagneticTargetSize() { - if (mTargetView == null) { - return; - } - - final Resources res = mContext.getResources(); - final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); - final FrameLayout.LayoutParams newParams = - new FrameLayout.LayoutParams(targetSize, targetSize); - newParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; - newParams.bottomMargin = mContext.getResources().getDimensionPixelSize( - R.dimen.floating_dismiss_bottom_margin); - mTargetView.setLayoutParams(newParams); - - // Set the magnetic field radius equal to the target size from the center of the target - mMagneticTarget.setMagneticFieldRadiusPx( - (int) (targetSize * MAGNETIC_FIELD_RADIUS_MULTIPLIER)); + mPipDismissTargetHandler.updateMagneticTargetSize(); } private boolean shouldShowResizeHandle() { @@ -368,7 +240,7 @@ public class PipTouchHandler { } public void onActivityPinned() { - createOrUpdateDismissTarget(); + mPipDismissTargetHandler.createOrUpdateDismissTarget(); mShowPipMenuOnAnimationEnd = true; mPipResizeGestureHandler.onActivityPinned(); @@ -378,7 +250,7 @@ public class PipTouchHandler { public void onActivityUnpinned(ComponentName topPipActivity) { if (topPipActivity == null) { // Clean up state after the last PiP activity is removed - cleanUpDismissTarget(); + mPipDismissTargetHandler.cleanUpDismissTarget(); mFloatingContentCoordinator.onContentRemoved(mMotionHelper); } @@ -409,7 +281,7 @@ public class PipTouchHandler { reloadResources(); // Recreate the dismiss target for the new orientation. - createOrUpdateDismissTarget(); + mPipDismissTargetHandler.createOrUpdateDismissTarget(); } public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { @@ -553,94 +425,6 @@ public class PipTouchHandler { } } - /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */ - private void createOrUpdateDismissTarget() { - if (!mTargetViewContainer.isAttachedToWindow()) { - mHandler.removeCallbacks(mShowTargetAction); - mMagneticTargetAnimator.cancel(); - - mTargetViewContainer.setVisibility(View.INVISIBLE); - - try { - mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams()); - } catch (IllegalStateException e) { - // This shouldn't happen, but if the target is already added, just update its layout - // params. - mWindowManager.updateViewLayout( - mTargetViewContainer, getDismissTargetLayoutParams()); - } - } else { - mWindowManager.updateViewLayout(mTargetViewContainer, getDismissTargetLayoutParams()); - } - } - - /** Returns layout params for the dismiss target, using the latest display metrics. */ - private WindowManager.LayoutParams getDismissTargetLayoutParams() { - final Point windowSize = new Point(); - mWindowManager.getDefaultDisplay().getRealSize(windowSize); - - final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - WindowManager.LayoutParams.MATCH_PARENT, - mDismissAreaHeight, - 0, windowSize.y - mDismissAreaHeight, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, - PixelFormat.TRANSLUCENT); - - lp.setTitle("pip-dismiss-overlay"); - lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - lp.setFitInsetsTypes(0 /* types */); - - return lp; - } - - /** Makes the dismiss target visible and animates it in, if it isn't already visible. */ - private void showDismissTargetMaybe() { - createOrUpdateDismissTarget(); - - if (mTargetViewContainer.getVisibility() != View.VISIBLE) { - - mTargetView.setTranslationY(mTargetViewContainer.getHeight()); - mTargetViewContainer.setVisibility(View.VISIBLE); - - // Cancel in case we were in the middle of animating it out. - mMagneticTargetAnimator.cancel(); - mMagneticTargetAnimator - .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig) - .start(); - - ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition( - DISMISS_TRANSITION_DURATION_MS); - } - } - - /** Animates the magnetic dismiss target out and then sets it to GONE. */ - private void hideDismissTarget() { - mHandler.removeCallbacks(mShowTargetAction); - mMagneticTargetAnimator - .spring(DynamicAnimation.TRANSLATION_Y, - mTargetViewContainer.getHeight(), - mTargetSpringConfig) - .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE)) - .start(); - - ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition( - DISMISS_TRANSITION_DURATION_MS); - } - - /** - * Removes the dismiss target and cancels any pending callbacks to show it. - */ - private void cleanUpDismissTarget() { - mHandler.removeCallbacks(mShowTargetAction); - - if (mTargetViewContainer.isAttachedToWindow()) { - mWindowManager.removeViewImmediate(mTargetViewContainer); - } - } - /** * TODO Add appropriate description */ @@ -650,7 +434,7 @@ public class PipTouchHandler { if (!isRegistered && mTouchState.isUserInteracting()) { // If the input consumer is unregistered while the user is interacting, then we may not // get the final TOUCH_UP event, so clean up the dismiss target as well - cleanUpDismissTarget(); + mPipDismissTargetHandler.cleanUpDismissTarget(); } } @@ -683,7 +467,7 @@ public class PipTouchHandler { } if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting()) - && mMagnetizedPip.maybeConsumeMotionEvent(ev)) { + && mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) { // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event // to the touch state. Touch state needs a DOWN event in order to later process MOVE // events it'll receive if the object is dragged out of the magnetic field. @@ -793,25 +577,6 @@ public class PipTouchHandler { } /** - * Updates the appearance of the menu and scrim on top of the PiP while dismissing. - */ - private void updateDismissFraction() { - if (mMenuController != null) { - Rect bounds = mMotionHelper.getBounds(); - final float target = mInsetBounds.bottom; - float fraction = 0f; - if (bounds.bottom > target) { - final float distance = bounds.bottom - target; - fraction = Math.min(distance / bounds.height(), 1f); - } - if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) { - // Update if the fraction > 0, or if fraction == 0 and the menu was already visible - mMenuController.setDismissFraction(fraction); - } - } - } - - /** * Sets the controller to update the system of changes from user interaction. */ void setPinnedStackController(IPinnedStackController controller) { @@ -958,13 +723,7 @@ public class PipTouchHandler { if (touchState.startedDragging()) { mSavedSnapFraction = -1f; - - if (mEnableDismissDragToEdge) { - if (mTargetViewContainer.getVisibility() != View.VISIBLE) { - mHandler.removeCallbacks(mShowTargetAction); - showDismissTargetMaybe(); - } - } + mPipDismissTargetHandler.showDismissTargetMaybe(); } if (touchState.isDragging()) { @@ -995,9 +754,7 @@ public class PipTouchHandler { @Override public boolean onUp(PipTouchState touchState) { - if (mEnableDismissDragToEdge) { - hideDismissTarget(); - } + mPipDismissTargetHandler.hideDismissTargetMaybe(); if (!touchState.isUserInteracting()) { return false; @@ -1023,12 +780,9 @@ public class PipTouchHandler { if (mEnableStash && (animatingBounds.right > mPipBoundsHandler.getDisplayBounds().right || animatingBounds.left < mPipBoundsHandler.getDisplayBounds().left)) { - mMotionHelper.stashToEdge(vel.x, vel.y, - PipTouchHandler.this::updateDismissFraction /* updateAction */, - this::flingEndAction /* endAction */); + mMotionHelper.stashToEdge(vel.x, vel.y, this::flingEndAction /* endAction */); } else { mMotionHelper.flingToSnapTarget(vel.x, vel.y, - PipTouchHandler.this::updateDismissFraction /* updateAction */, this::flingEndAction /* endAction */); } } else if (mTouchState.isDoubleTap()) { @@ -1122,7 +876,6 @@ public class PipTouchHandler { pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing); pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight); pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction); - pw.println(innerPrefix + "mEnableDragToEdgeDismiss=" + mEnableDismissDragToEdge); pw.println(innerPrefix + "mMovementBoundsExtraOffsets=" + mMovementBoundsExtraOffsets); mPipBoundsHandler.dump(pw, innerPrefix); mTouchState.dump(pw, innerPrefix); |