Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7f1942d authored by Liran Binyamin's avatar Liran Binyamin
Browse files

Let the bubble bar handle gestures over the bubble bar.

This change introduces a motion event flag to signal that the gesture
is being originated over the bubble bar (similar to the nav bar gesture flag). Downstream consumers use this flag to ignore the event in order
to allow the bubble bar to handle it.

The black screen in b/293348900 seemed to be related to the recents
shell transition closing the app that was in the foreground before
swiping on the bubble bar handle. Not sure why it ended up with a black
screen, but this change avoids starting the recents transition entirely.

Demo: http://recall/-/bJtug1HhvXkkeA4MQvIaiP/BSxLROoflr1i2yy0v6Y4G

Fixes: 294421126
Bug: 293348900
Test: Manual:
      - Add bubble to the bubble bar
      - Swipe up over the bubble bar
      - Observe that the bubble bar expands

      - Launch application
      - Swipe up on the bubble bar handle
      - Observe that the bubble bar expands

Change-Id: Iea15829de97edb6bfbfb7007388865230faaf736
parent 136bdf80
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -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.
     */
+6 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -191,8 +191,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
    public abstract boolean allowAllAppsFromOverview();

    public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
        TaskbarUIController controller = getTaskbarController();
        boolean isEventOverBubbleBarStashHandle =
                controller != null && controller.isEventOverBubbleBarStashHandle(ev);
        return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
                || isTrackpadMultiFingerSwipe(ev);
                || isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
    }

    /**
+89 −24
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
 */
package com.android.quickstep.inputconsumers;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;

import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
@@ -30,6 +33,7 @@ import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

import androidx.annotation.Nullable;

@@ -68,6 +72,9 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
    private final boolean mIsTaskbarAllAppsOpen;
    private boolean mHasPassedTaskbarNavThreshold;
    private boolean mIsInBubbleBarArea;
    private boolean mIsVerticalGestureOverBubbleBar;
    private boolean mIsPassedBubbleBarSlop;
    private final int mTouchSlop;

    private final PointF mDownPos = new PointF();
    private final PointF mLastPos = new PointF();
@@ -91,6 +98,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
        mOverviewCommandHelper = overviewCommandHelper;
        // TODO(b/270395798): remove this when cleaning up old Persistent Taskbar code.
        mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mScreenWidth = taskbarActivityContext.getDeviceProfile().widthPx;

        Resources res = context.getResources();
@@ -99,8 +107,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
                taskbarActivityContext.getDeviceProfile());
        mTaskbarNavThresholdY = taskbarActivityContext.getDeviceProfile().heightPx
                - mTaskbarNavThreshold;
        mIsTaskbarAllAppsOpen =
                mTaskbarActivityContext != null && mTaskbarActivityContext.isTaskbarAllAppsOpen();
        mIsTaskbarAllAppsOpen = mTaskbarActivityContext.isTaskbarAllAppsOpen();

        mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);

@@ -132,12 +139,8 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
        if (mState != STATE_ACTIVE) {
            boolean isStashedTaskbarHovered = isMouseEvent(ev)
                    && isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
            if (!isStashedTaskbarHovered) {
                mDelegate.onMotionEvent(ev);
            }

            // Only show the transient task bar if the touch events are on the screen.
            if (mTaskbarActivityContext != null && !isTrackpadMotionEvent(ev)) {
            if (!isTrackpadMotionEvent(ev)) {
                final float x = ev.getRawX();
                final float y = ev.getRawY();
                switch (ev.getAction()) {
@@ -193,14 +196,28 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
                        }
                        mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));

                        if (mIsTransientTaskbar) {
                        float dX = mLastPos.x - mDownPos.x;
                        float dY = mLastPos.y - mDownPos.y;

                        if (!mIsPassedBubbleBarSlop && mIsInBubbleBarArea) {
                            boolean passedSlop =
                                    Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
                            if (passedSlop) {
                                mIsPassedBubbleBarSlop = true;
                                mIsVerticalGestureOverBubbleBar = Math.abs(dY) > Math.abs(dX);
                                if (mIsVerticalGestureOverBubbleBar) {
                                    setActive(ev);
                                }
                            }
                        }

                        if (mIsTransientTaskbar) {
                            boolean passedTaskbarNavThreshold = dY < 0
                                    && Math.abs(dY) >= mTaskbarNavThreshold;

                            if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
                                mHasPassedTaskbarNavThreshold = true;
                                if (mIsInBubbleBarArea) {
                                if (mIsInBubbleBarArea && mIsVerticalGestureOverBubbleBar) {
                                    mTaskbarActivityContext.onSwipeToOpenBubblebar();
                                } else {
                                    mTaskbarActivityContext.onSwipeToUnstashTaskbar();
@@ -217,6 +234,55 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        cleanupAfterMotionEvent();
                        break;
                    case MotionEvent.ACTION_BUTTON_RELEASE:
                        if (isStashedTaskbarHovered) {
                            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
                        }
                        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);
@@ -228,15 +294,8 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
        }
        mHasPassedTaskbarNavThreshold = false;
        mIsInBubbleBarArea = false;
                        break;
                    case MotionEvent.ACTION_BUTTON_RELEASE:
                        if (isStashedTaskbarHovered) {
                            mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
                        }
                        break;
                }
            }
        }
        mIsVerticalGestureOverBubbleBar = false;
        mIsPassedBubbleBarSlop = false;
    }

    private boolean isInTaskbarArea(float x) {
@@ -246,13 +305,19 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
    }

    private boolean isInBubbleBarArea(float x) {
        if (mTaskbarActivityContext != null && mIsTransientTaskbar) {
        if (mTaskbarActivityContext == null || !mIsTransientTaskbar) {
            return false;
        }
        BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers();
            if (controllers == null) return false;
        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) {