From 7c10e48b42188659e15e1d643029b883a600a5d7 Mon Sep 17 00:00:00 2001 From: Ben Lin Date: Wed, 2 Sep 2020 12:56:12 -0700 Subject: [PATCH] Implement pinch to resize. Bug: 166478885 Test: adb shell cmd device_config put systemui pip_pinch_resize true Change-Id: Ide6fecd7a26c040b533fb49d399744c5617bfc93 --- .../sysui/SystemUiDeviceConfigFlags.java | 4 +- .../pip/phone/PipResizeGestureHandler.java | 172 +++++++++++++++--- .../systemui/pip/phone/PipTouchHandler.java | 3 +- 3 files changed, 146 insertions(+), 33 deletions(-) diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index da26930ca7273..8b4fddbec03ca 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -390,9 +390,9 @@ public final class SystemUiDeviceConfigFlags { public static final String CHOOSER_TARGET_RANKING_ENABLED = "chooser_target_ranking_enabled"; /** - * (boolean) Whether to enable user-drag resizing for PIP. + * (boolean) Whether to enable pinch resizing for PIP. */ - public static final String PIP_USER_RESIZE = "pip_user_resize"; + public static final String PIP_PINCH_RESIZE = "pip_pinch_resize"; /** * (float) Bottom height in DP for Back Gesture. diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java index 50d20d3572d1e..08d9b2ae21b00 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java @@ -15,7 +15,7 @@ */ package com.android.systemui.pip.phone; -import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_USER_RESIZE; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_PINCH_RESIZE; 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_NONE; @@ -46,6 +46,7 @@ import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputMonitor; import android.view.MotionEvent; +import android.view.ScaleGestureDetector; import android.view.ViewConfiguration; import com.android.internal.policy.TaskResizingAlgorithm; @@ -67,6 +68,8 @@ import java.util.function.Function; public class PipResizeGestureHandler { private static final String TAG = "PipResizeGestureHandler"; + private static final float PINCH_THRESHOLD = 0.05f; + private static final float STARTING_SCALE_FACTOR = 1.0f; private static final int INVALID_SYSUI_STATE_MASK = SYSUI_STATE_GLOBAL_ACTIONS_SHOWING @@ -83,6 +86,7 @@ public class PipResizeGestureHandler { private final int mDisplayId; private final Executor mMainExecutor; private final SysUiState mSysUiState; + private final ScaleGestureDetector mScaleGestureDetector; private final Region mTmpRegion = new Region(); private final PointF mDownPoint = new PointF(); @@ -105,8 +109,10 @@ public class PipResizeGestureHandler { private boolean mAllowGesture; private boolean mIsAttached; private boolean mIsEnabled; - private boolean mEnableUserResize; + private boolean mEnablePinchResize; private boolean mThresholdCrossed; + private boolean mUsingPinchToZoom = false; + private float mScaleFactor = STARTING_SCALE_FACTOR; private InputMonitor mInputMonitor; private InputEventReceiver mInputEventReceiver; @@ -136,17 +142,73 @@ public class PipResizeGestureHandler { context.getDisplay().getRealSize(mMaxSize); reloadResources(); - mEnableUserResize = DeviceConfig.getBoolean( + mScaleGestureDetector = new ScaleGestureDetector(context, + new ScaleGestureDetector.OnScaleGestureListener() { + @Override + public boolean onScale(ScaleGestureDetector detector) { + mScaleFactor *= detector.getScaleFactor(); + + if (!mThresholdCrossed + && (mScaleFactor > (STARTING_SCALE_FACTOR + PINCH_THRESHOLD) + || mScaleFactor < (STARTING_SCALE_FACTOR - PINCH_THRESHOLD))) { + mThresholdCrossed = true; + mInputMonitor.pilferPointers(); + } + if (mThresholdCrossed) { + int height = Math.min(mMaxSize.y, Math.max(mMinSize.y, + (int) (mScaleFactor * mLastDownBounds.height()))); + int width = Math.min(mMaxSize.x, Math.max(mMinSize.x, + (int) (mScaleFactor * mLastDownBounds.width()))); + int top, bottom, left, right; + + if ((mCtrlType & CTRL_TOP) != 0) { + top = mLastDownBounds.bottom - height; + bottom = mLastDownBounds.bottom; + } else { + top = mLastDownBounds.top; + bottom = mLastDownBounds.top + height; + } + + if ((mCtrlType & CTRL_LEFT) != 0) { + left = mLastDownBounds.right - width; + right = mLastDownBounds.right; + } else { + left = mLastDownBounds.left; + right = mLastDownBounds.left + width; + } + + mLastResizeBounds.set(left, top, right, bottom); + mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, + mLastResizeBounds, + null); + } + return true; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + setCtrlTypeForPinchToZoom(); + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + mScaleFactor = STARTING_SCALE_FACTOR; + finishResize(); + } + }); + + mEnablePinchResize = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, - PIP_USER_RESIZE, - /* defaultValue = */ true); + PIP_PINCH_RESIZE, + /* defaultValue = */ false); deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor, new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (properties.getKeyset().contains(PIP_USER_RESIZE)) { - mEnableUserResize = properties.getBoolean( - PIP_USER_RESIZE, /* defaultValue = */ true); + if (properties.getKeyset().contains(PIP_PINCH_RESIZE)) { + mEnablePinchResize = properties.getBoolean( + PIP_PINCH_RESIZE, /* defaultValue = */ false); } } }); @@ -193,7 +255,7 @@ public class PipResizeGestureHandler { } private void updateIsEnabled() { - boolean isEnabled = mIsAttached && mEnableUserResize; + boolean isEnabled = mIsAttached; if (isEnabled == mIsEnabled) { return; } @@ -211,7 +273,11 @@ public class PipResizeGestureHandler { private void onInputEvent(InputEvent ev) { if (ev instanceof MotionEvent) { - onMotionEvent((MotionEvent) ev); + if (mUsingPinchToZoom) { + mScaleGestureDetector.onTouchEvent((MotionEvent) ev); + } else { + onDragCornerResize((MotionEvent) ev); + } } } @@ -254,8 +320,51 @@ public class PipResizeGestureHandler { } public boolean willStartResizeGesture(MotionEvent ev) { - return mEnableUserResize && isInValidSysUiState() - && isWithinTouchRegion((int) ev.getRawX(), (int) ev.getRawY()); + if (isInValidSysUiState()) { + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + // Always pass the DOWN event to the ScaleGestureDetector + mScaleGestureDetector.onTouchEvent(ev); + if (isWithinTouchRegion((int) ev.getRawX(), (int) ev.getRawY())) { + return true; + } + break; + + case MotionEvent.ACTION_POINTER_DOWN: + if (mEnablePinchResize && ev.getPointerCount() == 2) { + mUsingPinchToZoom = true; + return true; + } + break; + + default: + break; + } + } + return false; + } + + private void setCtrlTypeForPinchToZoom() { + final Rect currentPipBounds = mMotionHelper.getBounds(); + mLastDownBounds.set(mMotionHelper.getBounds()); + + Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds); + mDisplayBounds.set(movementBounds.left, + movementBounds.top, + movementBounds.right + currentPipBounds.width(), + movementBounds.bottom + currentPipBounds.height()); + + if (currentPipBounds.left == mDisplayBounds.left) { + mCtrlType |= CTRL_RIGHT; + } else { + mCtrlType |= CTRL_LEFT; + } + + if (currentPipBounds.top > mDisplayBounds.top + mDisplayBounds.height()) { + mCtrlType |= CTRL_TOP; + } else { + mCtrlType |= CTRL_BOTTOM; + } } private void setCtrlType(int x, int y) { @@ -295,7 +404,7 @@ public class PipResizeGestureHandler { return (mSysUiState.getFlags() & INVALID_SYSUI_STATE_MASK) == 0; } - private void onMotionEvent(MotionEvent ev) { + private void onDragCornerResize(MotionEvent ev) { int action = ev.getActionMasked(); float x = ev.getX(); float y = ev.getY(); @@ -345,28 +454,33 @@ public class PipResizeGestureHandler { break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (!mLastResizeBounds.isEmpty()) { - mUserResizeBounds.set(mLastResizeBounds); - mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, - (Rect bounds) -> { - new Handler(Looper.getMainLooper()).post(() -> { - mMotionHelper.synchronizePinnedStackBounds(); - mUpdateMovementBoundsRunnable.run(); - resetState(); - }); - }); - mPipUiEventLogger.log( - PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE); - } else { - resetState(); - } + finishResize(); break; } } } + private void finishResize() { + if (!mLastResizeBounds.isEmpty()) { + mUserResizeBounds.set(mLastResizeBounds); + mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds, + (Rect bounds) -> { + new Handler(Looper.getMainLooper()).post(() -> { + mMotionHelper.synchronizePinnedStackBounds(); + mUpdateMovementBoundsRunnable.run(); + resetState(); + }); + }); + mPipUiEventLogger.log( + PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE); + } else { + resetState(); + } + } + private void resetState() { mCtrlType = CTRL_NONE; + mUsingPinchToZoom = false; mAllowGesture = false; mThresholdCrossed = false; } @@ -397,7 +511,7 @@ public class PipResizeGestureHandler { pw.println(innerPrefix + "mAllowGesture=" + mAllowGesture); pw.println(innerPrefix + "mIsAttached=" + mIsAttached); pw.println(innerPrefix + "mIsEnabled=" + mIsEnabled); - pw.println(innerPrefix + "mEnableUserResize=" + mEnableUserResize); + pw.println(innerPrefix + "mEnablePinchResize=" + mEnablePinchResize); pw.println(innerPrefix + "mThresholdCrossed=" + mThresholdCrossed); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 9693f235a4ff3..97b3484292c61 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -650,8 +650,7 @@ public class PipTouchHandler { } MotionEvent ev = (MotionEvent) inputEvent; - if (ev.getActionMasked() == MotionEvent.ACTION_DOWN - && mPipResizeGestureHandler.willStartResizeGesture(ev)) { + if (mPipResizeGestureHandler.willStartResizeGesture(ev)) { // Initialize the touch state for the gesture, but immediately reset to invalidate the // gesture mTouchState.onTouchEvent(ev);