summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-12 11:06:51 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-12 11:06:51 -0800
commitee4daa24e6baecd66df9350fc5fc1100453d7af6 (patch)
tree602750202d63f6c3ed40249bb158ecdbb7e734c0
parent02dec96abf10bb3c5df7f689ce386b60985c3752 (diff)
parent96b677267a871ca7999d0a82e042918909e0512b (diff)
Merge "[PiP2 on Desktop] Drag-corner-to-resize PiP." into main
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java218
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java129
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java196
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java5
6 files changed, 451 insertions, 108 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
index c10c2c905c97..c6afc313b239 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
@@ -81,8 +81,8 @@ public class PipDesktopState {
return false;
}
- /** Returns whether PiP is exiting while we're in a Desktop Mode session. */
- private boolean isPipExitingToDesktopMode() {
+ /** Returns whether PiP is active in a display that is in active Desktop Mode session. */
+ public boolean isPipInDesktopMode() {
// Early return if PiP in Desktop Windowing is not supported.
if (!isDesktopWindowingPipEnabled()) {
return false;
@@ -137,7 +137,7 @@ public class PipDesktopState {
// 1) If the display windowing mode is freeform, set windowing mode to UNDEFINED so it will
// resolve the windowing mode to the display's windowing mode.
// 2) If the display windowing mode is not FREEFORM, set windowing mode to FREEFORM.
- if (isPipExitingToDesktopMode()) {
+ if (isPipInDesktopMode()) {
if (isDisplayInFreeform()) {
return WINDOWING_MODE_UNDEFINED;
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index e7c76bbd91b2..7d80ee5f3bb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -174,6 +174,7 @@ public abstract class Pip2Module {
@NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
DisplayController displayController,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -182,8 +183,8 @@ public abstract class Pip2Module {
Optional<PipPerfHintController> pipPerfHintControllerOptional) {
return new PipTouchHandler(context, shellInit, shellCommandHandler, menuPhoneController,
pipBoundsAlgorithm, pipBoundsState, pipTransitionState, pipScheduler,
- sizeSpecSource, pipDisplayLayoutState, displayController, pipMotionHelper,
- floatingContentCoordinator, pipUiEventLogger, mainExecutor,
+ sizeSpecSource, pipDisplayLayoutState, pipDesktopState, displayController,
+ pipMotionHelper, floatingContentCoordinator, pipUiEventLogger, mainExecutor,
pipPerfHintControllerOptional);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java
new file mode 100644
index 000000000000..bd0b810b2a44
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDragToResizeHandler.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2025 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.pip2.phone;
+
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
+import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
+import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.MotionEvent;
+
+import com.android.internal.policy.TaskResizingAlgorithm;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.common.pip.PipBoundsState;
+
+import java.util.function.Function;
+
+/** Helper for handling drag-corner-to-resize gestures. */
+public class PipDragToResizeHandler {
+ private final Context mContext;
+ private final PipResizeGestureHandler mPipResizeGestureHandler;
+ private final PipBoundsState mPipBoundsState;
+ private final PhonePipMenuController mPhonePipMenuController;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private final PipScheduler mPipScheduler;
+
+ private final Region mTmpRegion = new Region();
+ private final Rect mDragCornerSize = new Rect();
+ private final Rect mTmpTopLeftCorner = new Rect();
+ private final Rect mTmpTopRightCorner = new Rect();
+ private final Rect mTmpBottomLeftCorner = new Rect();
+ private final Rect mTmpBottomRightCorner = new Rect();
+ private final Rect mDisplayBounds = new Rect();
+ private final Function<Rect, Rect> mMovementBoundsSupplier;
+ private int mDelta;
+
+ public PipDragToResizeHandler(Context context, PipResizeGestureHandler pipResizeGestureHandler,
+ PipBoundsState pipBoundsState,
+ PhonePipMenuController phonePipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
+ PipScheduler pipScheduler, Function<Rect, Rect> movementBoundsSupplier) {
+ mContext = context;
+ mPipResizeGestureHandler = pipResizeGestureHandler;
+ mPipBoundsState = pipBoundsState;
+ mPhonePipMenuController = phonePipMenuController;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
+ mPipScheduler = pipScheduler;
+ mMovementBoundsSupplier = movementBoundsSupplier;
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#reloadResources}. */
+ void reloadResources() {
+ final Resources res = mContext.getResources();
+ mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if drag-corner-to-resize is
+ * enabled. */
+ void onDragCornerResize(MotionEvent ev, Rect lastResizeBounds, PointF downPoint,
+ Rect downBounds, Point minSize, Point maxSize, float touchSlop) {
+ int action = ev.getActionMasked();
+ float x = ev.getX();
+ float y = ev.getY();
+ if (action == MotionEvent.ACTION_DOWN) {
+ lastResizeBounds.setEmpty();
+ final boolean allowGesture = isWithinDragResizeRegion((int) x, (int) y);
+ mPipResizeGestureHandler.setAllowGesture(allowGesture);
+ if (allowGesture) {
+ setCtrlType((int) x, (int) y);
+ downPoint.set(x, y);
+ downBounds.set(mPipBoundsState.getBounds());
+ }
+ } else if (mPipResizeGestureHandler.getAllowGesture()) {
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ // We do not support multi touch for resizing via drag
+ mPipResizeGestureHandler.setAllowGesture(false);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ final boolean thresholdCrossed = mPipResizeGestureHandler.getThresholdCrossed();
+ // Capture inputs
+ if (!mPipResizeGestureHandler.getThresholdCrossed()
+ && Math.hypot(x - downPoint.x, y - downPoint.y) > touchSlop) {
+ mPipResizeGestureHandler.setThresholdCrossed(true);
+ // Reset the down to begin resizing from this point
+ downPoint.set(x, y);
+ mPipResizeGestureHandler.pilferPointers();
+ }
+ if (mPipResizeGestureHandler.getThresholdCrossed()) {
+ if (mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu(ANIM_TYPE_NONE,
+ false /* resize */);
+ }
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ lastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
+ downPoint.x, downPoint.y, currentPipBounds,
+ mPipResizeGestureHandler.getCtrlType(), minSize.x,
+ minSize.y, maxSize, true,
+ downBounds.width() > downBounds.height()));
+ mPipBoundsAlgorithm.transformBoundsToAspectRatio(lastResizeBounds,
+ mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+ true /* useCurrentSize */);
+ mPipScheduler.scheduleUserResizePip(lastResizeBounds);
+ mPipBoundsState.setHasUserResizedPip(true);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mPipResizeGestureHandler.finishResize();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Check whether the current x,y coordinate is within the region in which drag-resize should
+ * start.
+ * This consists of 4 small squares on the 4 corners of the PIP window, a quarter of which
+ * overlaps with the PIP window while the rest goes outside of the PIP window.
+ * _ _ _ _
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ * | PIP |
+ * | WINDOW |
+ * _|_ _|_
+ * |_|_|_________|_|_|
+ * |_|_| |_|_|
+ */
+ boolean isWithinDragResizeRegion(int x, int y) {
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ if (currentPipBounds == null) {
+ return false;
+ }
+ resetDragCorners();
+ mTmpTopLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpTopRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.top - mDelta / 2);
+ mTmpBottomLeftCorner.offset(currentPipBounds.left - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
+ mTmpBottomRightCorner.offset(currentPipBounds.right - mDelta / 2,
+ currentPipBounds.bottom - mDelta / 2);
+
+ mTmpRegion.setEmpty();
+ mTmpRegion.op(mTmpTopLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpTopRightCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomLeftCorner, Region.Op.UNION);
+ mTmpRegion.op(mTmpBottomRightCorner, Region.Op.UNION);
+
+ return mTmpRegion.contains(x, y);
+ }
+
+ private void resetDragCorners() {
+ mDragCornerSize.set(0, 0, mDelta, mDelta);
+ mTmpTopLeftCorner.set(mDragCornerSize);
+ mTmpTopRightCorner.set(mDragCornerSize);
+ mTmpBottomLeftCorner.set(mDragCornerSize);
+ mTmpBottomRightCorner.set(mDragCornerSize);
+ }
+
+ private void setCtrlType(int x, int y) {
+ final Rect currentPipBounds = mPipBoundsState.getBounds();
+ int ctrlType = mPipResizeGestureHandler.getCtrlType();
+
+ Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds);
+
+ mDisplayBounds.set(movementBounds.left,
+ movementBounds.top,
+ movementBounds.right + currentPipBounds.width(),
+ movementBounds.bottom + currentPipBounds.height());
+
+ if (mTmpTopLeftCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.left != mDisplayBounds.left) {
+ ctrlType |= CTRL_LEFT;
+ ctrlType |= CTRL_TOP;
+ }
+ if (mTmpTopRightCorner.contains(x, y) && currentPipBounds.top != mDisplayBounds.top
+ && currentPipBounds.right != mDisplayBounds.right) {
+ ctrlType |= CTRL_RIGHT;
+ ctrlType |= CTRL_TOP;
+ }
+ if (mTmpBottomRightCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.right != mDisplayBounds.right) {
+ ctrlType |= CTRL_RIGHT;
+ ctrlType |= CTRL_BOTTOM;
+ }
+ if (mTmpBottomLeftCorner.contains(x, y)
+ && currentPipBounds.bottom != mDisplayBounds.bottom
+ && currentPipBounds.left != mDisplayBounds.left) {
+ ctrlType |= CTRL_LEFT;
+ ctrlType |= CTRL_BOTTOM;
+ }
+
+ mPipResizeGestureHandler.setCtrlType(ctrlType);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java
new file mode 100644
index 000000000000..1e41af379864
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipPinchToResizeHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2025 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.pip2.phone;
+
+import android.graphics.Point;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm;
+
+/** Helper for handling pinch-to-resize gestures. */
+public class PipPinchToResizeHandler {
+ private final PipResizeGestureHandler mPipResizeGestureHandler;
+ private final PipBoundsState mPipBoundsState;
+ private final PhonePipMenuController mPhonePipMenuController;
+ private final PipScheduler mPipScheduler;
+ private final PipPinchResizingAlgorithm mPinchResizingAlgorithm;
+
+ private int mFirstIndex = -1;
+ private int mSecondIndex = -1;
+
+ public PipPinchToResizeHandler(PipResizeGestureHandler pipResizeGestureHandler,
+ PipBoundsState pipBoundsState, PhonePipMenuController phonePipMenuController,
+ PipScheduler pipScheduler) {
+ mPipResizeGestureHandler = pipResizeGestureHandler;
+ mPipBoundsState = pipBoundsState;
+ mPhonePipMenuController = phonePipMenuController;
+ mPipScheduler = pipScheduler;
+
+ mPinchResizingAlgorithm = new PipPinchResizingAlgorithm();
+ }
+
+ /** Invoked by {@link PipResizeGestureHandler#onInputEvent} if pinch-to-resize is enabled. */
+ void onPinchResize(MotionEvent ev, PointF downPoint, PointF downSecondPoint, Rect downBounds,
+ PointF lastPoint, PointF lastSecondPoint, Rect lastResizeBounds, float touchSlop,
+ Point minSize, Point maxSize) {
+ int action = ev.getActionMasked();
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mFirstIndex = -1;
+ mSecondIndex = -1;
+ mPipResizeGestureHandler.setAllowGesture(false);
+ mPipResizeGestureHandler.finishResize();
+ }
+
+ if (ev.getPointerCount() != 2) {
+ return;
+ }
+
+ final Rect pipBounds = mPipBoundsState.getBounds();
+ if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ if (mFirstIndex == -1 && mSecondIndex == -1
+ && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0))
+ && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) {
+ mPipResizeGestureHandler.setAllowGesture(true);
+ mFirstIndex = 0;
+ mSecondIndex = 1;
+ downPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
+ downSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
+ downBounds.set(pipBounds);
+
+ lastPoint.set(downPoint);
+ lastSecondPoint.set(lastSecondPoint);
+ lastResizeBounds.set(downBounds);
+
+ // start the high perf session as the second pointer gets detected
+ mPipResizeGestureHandler.startHighPerfSession();
+ }
+ }
+
+ if (action == MotionEvent.ACTION_MOVE) {
+ if (mFirstIndex == -1 || mSecondIndex == -1) {
+ return;
+ }
+
+ float x0 = ev.getRawX(mFirstIndex);
+ float y0 = ev.getRawY(mFirstIndex);
+ float x1 = ev.getRawX(mSecondIndex);
+ float y1 = ev.getRawY(mSecondIndex);
+ lastPoint.set(x0, y0);
+ lastSecondPoint.set(x1, y1);
+
+ // Capture inputs
+ if (!mPipResizeGestureHandler.getThresholdCrossed()
+ && (distanceBetween(downSecondPoint, lastSecondPoint) > touchSlop
+ || distanceBetween(downPoint, lastPoint) > touchSlop)) {
+ mPipResizeGestureHandler.pilferPointers();
+ mPipResizeGestureHandler.setThresholdCrossed(true);
+ // Reset the down to begin resizing from this point
+ downPoint.set(lastPoint);
+ downSecondPoint.set(lastSecondPoint);
+
+ if (mPhonePipMenuController.isMenuVisible()) {
+ mPhonePipMenuController.hideMenu();
+ }
+ }
+
+ if (mPipResizeGestureHandler.getThresholdCrossed()) {
+ final float angle = mPinchResizingAlgorithm.calculateBoundsAndAngle(downPoint,
+ downSecondPoint, lastPoint, lastSecondPoint, minSize, maxSize,
+ downBounds, lastResizeBounds);
+
+ mPipResizeGestureHandler.setAngle(angle);
+ mPipScheduler.scheduleUserResizePip(lastResizeBounds, angle);
+ mPipBoundsState.setHasUserResizedPip(true);
+ }
+ }
+ }
+
+ private float distanceBetween(PointF p1, PointF p2) {
+ return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
index e4be3f60f86e..b869bf153c34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
@@ -44,13 +44,14 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDesktopState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipPerfHintController;
-import com.android.wm.shell.common.pip.PipPinchResizingAlgorithm;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import java.io.PrintWriter;
+import java.util.function.Function;
/**
* Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to
@@ -72,8 +73,8 @@ public class PipResizeGestureHandler implements
private final PipTransitionState mPipTransitionState;
private final PhonePipMenuController mPhonePipMenuController;
private final PipDisplayLayoutState mPipDisplayLayoutState;
+ private final PipDesktopState mPipDesktopState;
private final PipUiEventLogger mPipUiEventLogger;
- private final PipPinchResizingAlgorithm mPinchResizingAlgorithm;
private final ShellExecutor mMainExecutor;
private final PointF mDownPoint = new PointF();
@@ -93,16 +94,18 @@ public class PipResizeGestureHandler implements
private boolean mIsAttached;
private boolean mIsEnabled;
private boolean mEnablePinchResize;
+ private boolean mEnableDragCornerResize;
private boolean mIsSysUiStateValid;
private boolean mThresholdCrossed;
private boolean mOngoingPinchToResize = false;
private boolean mWaitingForBoundsChangeTransition = false;
private float mAngle = 0;
- int mFirstIndex = -1;
- int mSecondIndex = -1;
+
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
+ private PipDragToResizeHandler mPipDragToResizeHandler;
+ private PipPinchToResizeHandler mPipPinchToResizeHandler;
@Nullable
private final PipPerfHintController mPipPerfHintController;
@@ -121,7 +124,9 @@ public class PipResizeGestureHandler implements
PipTransitionState pipTransitionState,
PipUiEventLogger pipUiEventLogger,
PhonePipMenuController menuActivityController,
+ Function<Rect, Rect> movementBoundsSupplier,
PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
ShellExecutor mainExecutor,
@Nullable PipPerfHintController pipPerfHintController) {
mContext = context;
@@ -137,8 +142,13 @@ public class PipResizeGestureHandler implements
mPhonePipMenuController = menuActivityController;
mPipDisplayLayoutState = pipDisplayLayoutState;
+ mPipDesktopState = pipDesktopState;
mPipUiEventLogger = pipUiEventLogger;
- mPinchResizingAlgorithm = new PipPinchResizingAlgorithm();
+
+ mPipDragToResizeHandler = new PipDragToResizeHandler(context, this, pipBoundsState,
+ menuActivityController, pipBoundsAlgorithm, pipScheduler, movementBoundsSupplier);
+ mPipPinchToResizeHandler = new PipPinchToResizeHandler(this, pipBoundsState,
+ menuActivityController, pipScheduler);
}
void init() {
@@ -163,6 +173,7 @@ public class PipResizeGestureHandler implements
}
private void reloadResources() {
+ mPipDragToResizeHandler.reloadResources();
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
@@ -180,6 +191,8 @@ public class PipResizeGestureHandler implements
void onActivityPinned() {
mIsAttached = true;
updateIsEnabled();
+ // Only enable drag-corner-to-resize if PiP was entered when Desktop Mode session is active.
+ mEnableDragCornerResize = mPipDesktopState.isPipInDesktopMode();
}
void onActivityUnpinned() {
@@ -211,9 +224,44 @@ public class PipResizeGestureHandler implements
}
}
+ boolean getAllowGesture() {
+ return mAllowGesture;
+ }
+
+ void setAllowGesture(boolean allowGesture) {
+ mAllowGesture = allowGesture;
+ }
+
+ boolean getThresholdCrossed() {
+ return mThresholdCrossed;
+ }
+
+ void setThresholdCrossed(boolean thresholdCrossed) {
+ mThresholdCrossed = thresholdCrossed;
+ }
+
+ int getCtrlType() {
+ return mCtrlType;
+ }
+
+ void setCtrlType(int ctrlType) {
+ mCtrlType = ctrlType;
+ }
+
+ void setAngle(float angle) {
+ mAngle = angle;
+ }
+
+ void startHighPerfSession() {
+ if (mPipPerfHintController != null) {
+ mPipHighPerfSession = mPipPerfHintController.startSession(
+ this::onHighPerfSessionTimeout, "onPinchResize");
+ }
+ }
+
@VisibleForTesting
void onInputEvent(InputEvent ev) {
- if (!mEnablePinchResize) {
+ if (!mEnableDragCornerResize && !mEnablePinchResize) {
// No need to handle anything if resizing isn't enabled.
return;
}
@@ -240,7 +288,12 @@ public class PipResizeGestureHandler implements
}
if (mOngoingPinchToResize) {
- onPinchResize(mv);
+ mPipPinchToResizeHandler.onPinchResize(mv, mDownPoint, mDownSecondPoint,
+ mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds, mTouchSlop,
+ mMinSize, mMaxSize);
+ } else if (mEnableDragCornerResize) {
+ mPipDragToResizeHandler.onDragCornerResize(mv, mLastResizeBounds, mDownPoint,
+ mDownBounds, mMinSize, mMaxSize, mTouchSlop);
}
}
}
@@ -261,20 +314,31 @@ public class PipResizeGestureHandler implements
}
boolean willStartResizeGesture(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
- if (mEnablePinchResize && ev.getPointerCount() == 2) {
- onPinchResize(ev);
- mOngoingPinchToResize = mAllowGesture;
- return mAllowGesture;
- }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ if (mEnableDragCornerResize && mPipDragToResizeHandler.isWithinDragResizeRegion(
+ (int) ev.getRawX(),
+ (int) ev.getRawY())) {
+ return true;
+ }
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN:
+ if (mEnablePinchResize && ev.getPointerCount() == 2) {
+ mPipPinchToResizeHandler.onPinchResize(ev, mDownPoint, mDownSecondPoint,
+ mDownBounds, mLastPoint, mLastSecondPoint, mLastResizeBounds,
+ mTouchSlop, mMinSize, mMaxSize);
+ mOngoingPinchToResize = mAllowGesture;
+ return mAllowGesture;
+ }
+ break;
+
+ default:
+ break;
}
return false;
}
- private boolean isInValidSysUiState() {
- return mIsSysUiStateValid;
- }
-
private void onHighPerfSessionTimeout(PipPerfHintController.PipHighPerfSession session) {}
private void cleanUpHighPerfSessionMaybe() {
@@ -285,83 +349,6 @@ public class PipResizeGestureHandler implements
}
}
- @VisibleForTesting
- void onPinchResize(MotionEvent ev) {
- int action = ev.getActionMasked();
-
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mFirstIndex = -1;
- mSecondIndex = -1;
- mAllowGesture = false;
- finishResize();
- }
-
- if (ev.getPointerCount() != 2) {
- return;
- }
-
- final Rect pipBounds = mPipBoundsState.getBounds();
- if (action == MotionEvent.ACTION_POINTER_DOWN) {
- if (mFirstIndex == -1 && mSecondIndex == -1
- && pipBounds.contains((int) ev.getRawX(0), (int) ev.getRawY(0))
- && pipBounds.contains((int) ev.getRawX(1), (int) ev.getRawY(1))) {
- mAllowGesture = true;
- mFirstIndex = 0;
- mSecondIndex = 1;
- mDownPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
- mDownSecondPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
- mDownBounds.set(pipBounds);
-
- mLastPoint.set(mDownPoint);
- mLastSecondPoint.set(mLastSecondPoint);
- mLastResizeBounds.set(mDownBounds);
-
- // start the high perf session as the second pointer gets detected
- if (mPipPerfHintController != null) {
- mPipHighPerfSession = mPipPerfHintController.startSession(
- this::onHighPerfSessionTimeout, "onPinchResize");
- }
- }
- }
-
- if (action == MotionEvent.ACTION_MOVE) {
- if (mFirstIndex == -1 || mSecondIndex == -1) {
- return;
- }
-
- float x0 = ev.getRawX(mFirstIndex);
- float y0 = ev.getRawY(mFirstIndex);
- float x1 = ev.getRawX(mSecondIndex);
- float y1 = ev.getRawY(mSecondIndex);
- mLastPoint.set(x0, y0);
- mLastSecondPoint.set(x1, y1);
-
- // Capture inputs
- if (!mThresholdCrossed
- && (distanceBetween(mDownSecondPoint, mLastSecondPoint) > mTouchSlop
- || distanceBetween(mDownPoint, mLastPoint) > mTouchSlop)) {
- pilferPointers();
- mThresholdCrossed = true;
- // Reset the down to begin resizing from this point
- mDownPoint.set(mLastPoint);
- mDownSecondPoint.set(mLastSecondPoint);
-
- if (mPhonePipMenuController.isMenuVisible()) {
- mPhonePipMenuController.hideMenu();
- }
- }
-
- if (mThresholdCrossed) {
- mAngle = mPinchResizingAlgorithm.calculateBoundsAndAngle(mDownPoint,
- mDownSecondPoint, mLastPoint, mLastSecondPoint, mMinSize, mMaxSize,
- mDownBounds, mLastResizeBounds);
-
- mPipScheduler.scheduleUserResizePip(mLastResizeBounds, mAngle);
- mPipBoundsState.setHasUserResizedPip(true);
- }
- }
- }
-
private void snapToMovementBoundsEdge(Rect bounds, Rect movementBounds) {
final int leftEdge = bounds.left;
@@ -404,17 +391,21 @@ public class PipResizeGestureHandler implements
// mPipTaskOrganizer.scheduleFinishResizePip(finalBounds, mUpdateResizeBoundsCallback);
}
- private void finishResize() {
+ /** Handles additional resizing and state changes after gesture resizing is done. */
+ void finishResize() {
if (mLastResizeBounds.isEmpty()) {
resetState();
}
- if (!mOngoingPinchToResize) {
- return;
- }
// Cache initial bounds after release for animation before mLastResizeBounds are modified.
mStartBoundsAfterRelease.set(mLastResizeBounds);
+ // Drag-corner-to-resize - we don't need to adjust the bounds at this point
+ if (!mOngoingPinchToResize) {
+ scheduleBoundsChange();
+ return;
+ }
+
// If user resize is pretty close to max size, just auto resize to max.
if (mLastResizeBounds.width() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.x
|| mLastResizeBounds.height() >= PINCH_RESIZE_AUTO_MAX_RATIO * mMaxSize.y) {
@@ -438,6 +429,10 @@ public class PipResizeGestureHandler implements
mLastResizeBounds, movementBounds);
mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
+ scheduleBoundsChange();
+ }
+
+ private void scheduleBoundsChange() {
// Update the transition state to schedule a resize transition.
Bundle extra = new Bundle();
extra.putBoolean(RESIZE_BOUNDS_CHANGE, true);
@@ -489,10 +484,6 @@ public class PipResizeGestureHandler implements
mOhmOffset = offset;
}
- private float distanceBetween(PointF p1, PointF p2) {
- return (float) Math.hypot(p2.x - p1.x, p2.y - p1.y);
- }
-
private void resizeRectAboutCenter(Rect rect, int w, int h) {
int cx = rect.centerX();
int cy = rect.centerY();
@@ -573,6 +564,7 @@ public class PipResizeGestureHandler implements
pw.println(innerPrefix + "mIsAttached=" + mIsAttached);
pw.println(innerPrefix + "mIsEnabled=" + mIsEnabled);
pw.println(innerPrefix + "mEnablePinchResize=" + mEnablePinchResize);
+ pw.println(innerPrefix + "mEnableDragCornerResize=" + mEnableDragCornerResize);
pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed);
pw.println(innerPrefix + "mOhmOffset=" + mOhmOffset);
pw.println(innerPrefix + "mMinSize=" + mMinSize);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index e405f3339054..72346b335a8e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -59,6 +59,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipDesktopState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipDoubleTapHelper;
import com.android.wm.shell.common.pip.PipPerfHintController;
@@ -187,6 +188,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
@NonNull PipScheduler pipScheduler,
@NonNull SizeSpecSource sizeSpecSource,
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ PipDesktopState pipDesktopState,
DisplayController displayController,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -226,7 +228,8 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
mainExecutor);
mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsAlgorithm,
pipBoundsState, mTouchState, mPipScheduler, mPipTransitionState, pipUiEventLogger,
- menuController, mPipDisplayLayoutState, mainExecutor, mPipPerfHintController);
+ menuController, this::getMovementBounds, mPipDisplayLayoutState, pipDesktopState,
+ mainExecutor, mPipPerfHintController);
mPipBoundsState.addOnAspectRatioChangedCallback(aspectRatio -> {
updateMinMaxSize(aspectRatio);
onAspectRatioChanged();