diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 139e8f0c98..445b312424 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -155,7 +155,7 @@ public class TaskbarUIController { mControllers.taskbarActivityContext.startTranslationSpring(); } - /* + /** * @param ev MotionEvent in screen coordinates. * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. */ @@ -164,6 +164,14 @@ public class TaskbarUIController { || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev); } + /** Checks if the given {@link MotionEvent} is over the bubble bar stash handle. */ + public boolean isEventOverBubbleBarStashHandle(MotionEvent ev) { + return mControllers.bubbleControllers.map( + bubbleControllers -> + bubbleControllers.bubbleStashController.isEventOverStashHandle(ev)) + .orElse(false); + } + /** * Returns true if icons should be aligned to hotseat in the current transition. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java index a5ea5a9955..09021edb91 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java @@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.annotation.Nullable; import android.view.InsetsController; +import android.view.MotionEvent; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.StashedHandleViewController; @@ -350,4 +351,9 @@ public class BubbleStashController { return mBubblesShowingOnHome ? getBubbleBarTranslationYForHotseat() : getBubbleBarTranslationYForTaskbar(); } + + /** Checks whether the motion event is over the stash handle. */ + public boolean isEventOverStashHandle(MotionEvent ev) { + return mHandleViewController.isEventOverHandle(ev); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java index fbab59531c..c998d9704e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java @@ -24,6 +24,7 @@ import android.animation.ValueAnimator; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; +import android.view.MotionEvent; import android.view.View; import android.view.ViewOutlineProvider; @@ -268,4 +269,22 @@ public class BubbleStashedHandleViewController { }); return revealAnim; } + + /** Checks that the stash handle is visible and that the motion event is within bounds. */ + public boolean isEventOverHandle(MotionEvent ev) { + if (mStashedHandleView.getVisibility() != VISIBLE) { + return false; + } + + // the bounds of the handle only include the visible part, so we check that the Y coordinate + // is anywhere within the stashed taskbar height. + int top = mActivity.getDeviceProfile().heightPx - mStashedTaskbarHeight; + + return (int) ev.getRawY() >= top && containsX((int) ev.getRawX()); + } + + /** Checks if the given x coordinate is within the stashed handle bounds. */ + public boolean containsX(int x) { + return x >= mStashedHandleBounds.left && x <= mStashedHandleBounds.right; + } } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 3f8813990f..8925bd61e2 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -191,8 +191,11 @@ public abstract class BaseActivityInterface mTouchSlop || Math.abs(dX) > mTouchSlop; + if (passedSlop) { + mIsPassedBubbleBarSlop = true; + mIsVerticalGestureOverBubbleBar = Math.abs(dY) > Math.abs(dX); + if (mIsVerticalGestureOverBubbleBar) { + setActive(ev); + } + } + } + if (mIsTransientTaskbar) { - float dY = mLastPos.y - mDownPos.y; boolean passedTaskbarNavThreshold = dY < 0 && Math.abs(dY) >= mTaskbarNavThreshold; if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) { mHasPassedTaskbarNavThreshold = true; - if (mIsInBubbleBarArea) { + if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) { mTaskbarActivityContext.onSwipeToOpenBubblebar(); } else { mTaskbarActivityContext.onSwipeToUnstashTaskbar(); @@ -217,17 +234,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (!mIsTransientTaskbar && !mCanceledUnstashHint) { - mTaskbarActivityContext.startTaskbarUnstashHint( - /* animateForward = */ false); - } - mTaskbarActivityContext.setAutohideSuspendFlag( - FLAG_AUTOHIDE_SUSPEND_TOUCHING, false); - if (mTransitionCallback != null) { - mTransitionCallback.onActionEnd(); - } - mHasPassedTaskbarNavThreshold = false; - mIsInBubbleBarArea = false; + cleanupAfterMotionEvent(); break; case MotionEvent.ACTION_BUTTON_RELEASE: if (isStashedTaskbarHovered) { @@ -236,9 +243,61 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { break; } } + boolean isMovingInBubbleBarArea = mIsInBubbleBarArea && ev.getAction() == ACTION_MOVE; + if (!isStashedTaskbarHovered) { + // if we're moving in the bubble bar area but we haven't passed the slop yet, don't + // propagate to the delegate, until we can determine the direction of the gesture. + if (!isMovingInBubbleBarArea || mIsPassedBubbleBarSlop) { + mDelegate.onMotionEvent(ev); + } + } + } else if (mIsVerticalGestureOverBubbleBar) { + // if we get here then this gesture is a vertical swipe over the bubble bar. + // we're also active and there's no need to delegate any additional motion events. the + // rest of the gesture will be handled here. + switch (ev.getAction()) { + case ACTION_MOVE: + int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == INVALID_POINTER_ID) { + break; + } + mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex)); + + float dY = mLastPos.y - mDownPos.y; + + // bubble bar swipe gesture uses the same threshold as the taskbar. + boolean passedTaskbarNavThreshold = dY < 0 + && Math.abs(dY) >= mTaskbarNavThreshold; + + if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) { + mHasPassedTaskbarNavThreshold = true; + mTaskbarActivityContext.onSwipeToOpenBubblebar(); + } + break; + case ACTION_UP: + case ACTION_CANCEL: + cleanupAfterMotionEvent(); + break; + } } } + private void cleanupAfterMotionEvent() { + if (!mIsTransientTaskbar && !mCanceledUnstashHint) { + mTaskbarActivityContext.startTaskbarUnstashHint( + /* animateForward = */ false); + } + mTaskbarActivityContext.setAutohideSuspendFlag( + FLAG_AUTOHIDE_SUSPEND_TOUCHING, false); + if (mTransitionCallback != null) { + mTransitionCallback.onActionEnd(); + } + mHasPassedTaskbarNavThreshold = false; + mIsInBubbleBarArea = false; + mIsVerticalGestureOverBubbleBar = false; + mIsPassedBubbleBarSlop = false; + } + private boolean isInTaskbarArea(float x) { float areaFromMiddle = mUnstashArea / 2.0f; float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x); @@ -246,13 +305,19 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { } private boolean isInBubbleBarArea(float x) { - if (mTaskbarActivityContext != null && mIsTransientTaskbar) { - BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers(); - if (controllers == null) return false; + if (mTaskbarActivityContext == null || !mIsTransientTaskbar) { + return false; + } + BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers(); + if (controllers == null) { + return false; + } + if (controllers.bubbleStashController.isStashed()) { + return controllers.bubbleStashedHandleViewController.containsX((int) x); + } else { Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds(); return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right; } - return false; } private void onLongPressDetected(MotionEvent motionEvent) {