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

Commit 49658847 authored by Winson Chung's avatar Winson Chung
Browse files

Fix issue with quickswitch happening after recents animation starting



- When the animation starts, prevent quickswitch until the next gesture
  starts
- Refactor recents animation started signal into the gesture helper to
  simplify the code in the nav bar view

Bug: 67957962
Bug: 70180755
Bug: 73080940
Test: Quick scrub on nav bar

Change-Id: I718d3e64c14569e5df2e6a0ffc1aecdb0125f54f
Signed-off-by: default avatarWinson Chung <winsonc@google.com>
parent de2a1248
Loading
Loading
Loading
Loading
+31 −0
Original line number Original line Diff line number Diff line
@@ -21,9 +21,40 @@ import com.android.systemui.shared.recents.ISystemUiProxy;


oneway interface IOverviewProxy {
oneway interface IOverviewProxy {
    void onBind(in ISystemUiProxy sysUiProxy);
    void onBind(in ISystemUiProxy sysUiProxy);

    /**
     * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
     * guarantees the following order of events:
     *
     * Normal gesture: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, UP
     * Quick switch: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SWITCH
     * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
     *
     * Once quick switch/scrub is sent, then no further motion events will be provided.
     */
    void onMotionEvent(in MotionEvent event);
    void onMotionEvent(in MotionEvent event);

    /**
     * Sent when a user has quickly flinged on the nav bar to switch tasks. Once this event is sent
     * the caller will stop sending any motion events.
     */
    void onQuickSwitch();
    void onQuickSwitch();

    /**
     * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
     * sent the caller will stop sending any motion events.
     */
    void onQuickScrubStart();
    void onQuickScrubStart();

    /**
     * Sent when the user stops actively scrubbing the nav bar to switch tasks. Once this event is
     * sent the caller will stop sending any motion events.
     */
    void onQuickScrubEnd();
    void onQuickScrubEnd();

    /**
     * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks. Once
     * this event is sent the caller will stop sending any motion events.
     */
    void onQuickScrubProgress(float progress);
    void onQuickScrubProgress(float progress);
}
}
+37 −14
Original line number Original line Diff line number Diff line
@@ -16,37 +16,37 @@


package com.android.systemui.statusbar.phone;
package com.android.systemui.statusbar.phone;


import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;

import android.app.ActivityManager;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.util.Log;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View;

import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.Dependency;
import com.android.systemui.Dependency;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.R;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService;


import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
import static com.android.systemui.OverviewProxyService.TAG_OPS;

/**
/**
 * Class to detect gestures on the navigation bar.
 * Class to detect gestures on the navigation bar.
 */
 */
@@ -84,8 +84,16 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
    private int mTouchDownY;
    private int mTouchDownY;
    private boolean mDownOnRecents;
    private boolean mDownOnRecents;
    private VelocityTracker mVelocityTracker;
    private VelocityTracker mVelocityTracker;
    private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
    private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class);
    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
        @Override
        public void onRecentsAnimationStarted() {
            mRecentsAnimationStarted = true;
            mQuickScrubController.cancelQuickSwitch();
        }
    };


    private boolean mRecentsAnimationStarted;
    private boolean mDockWindowEnabled;
    private boolean mDockWindowEnabled;
    private boolean mDockWindowTouchSlopExceeded;
    private boolean mDockWindowTouchSlopExceeded;
    private int mDragMode;
    private int mDragMode;
@@ -97,10 +105,12 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
        mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
        mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
        mQuickScrubController = new QuickScrubController(context);
        mQuickScrubController = new QuickScrubController(context);
        Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
        Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
        mOverviewProxyService.addCallback(mOverviewProxyListener);
    }
    }


    public void destroy() {
    public void destroy() {
        Dependency.get(TunerService.class).removeTunable(this);
        Dependency.get(TunerService.class).removeTunable(this);
        mOverviewProxyService.removeCallback(mOverviewProxyListener);
    }
    }


    public void setComponents(RecentsComponent recentsComponent, Divider divider,
    public void setComponents(RecentsComponent recentsComponent, Divider divider,
@@ -117,7 +127,7 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
    }
    }


    private boolean proxyMotionEvents(MotionEvent event) {
    private boolean proxyMotionEvents(MotionEvent event) {
        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
        final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
        if (overviewProxy != null) {
        if (overviewProxy != null) {
            mNavigationBarView.requestUnbufferedDispatch(event);
            mNavigationBarView.requestUnbufferedDispatch(event);
            event.transform(mTransformGlobalMatrix);
            event.transform(mTransformGlobalMatrix);
@@ -146,6 +156,19 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
                mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
                mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
                mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
                mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
                mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
                mRecentsAnimationStarted = false;
                break;
            }
            case MotionEvent.ACTION_UP: {
                // If the overview proxy service has not started the recents animation then clean up
                // after it to ensure that the nav bar buttons still work
                if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
                    try {
                        ActivityManager.getService().cancelRecentsAnimation();
                    } catch (RemoteException e) {
                        Log.e(TAG, "Could not cancel recents animation", e);
                    }
                }
                break;
                break;
            }
            }
        }
        }
@@ -154,13 +177,13 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
            proxyMotionEvents(event);
            proxyMotionEvents(event);
            return false;
            return false;
        }
        }
        return (mDockWindowEnabled && interceptDockWindowEvent(event));
        return (mDockWindowEnabled && interceptDockWindowEvent(event)) || mRecentsAnimationStarted;
    }
    }


    public boolean onTouchEvent(MotionEvent event) {
    public boolean onTouchEvent(MotionEvent event) {
        // The same down event was just sent on intercept and therefore can be ignored here
        // The same down event was just sent on intercept and therefore can be ignored here
        boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
        boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
                && mOverviewEventSender.getProxy() != null;
                && mOverviewProxyService.getProxy() != null;
        boolean result = mStatusBar.isPresenterFullyCollapsed()
        boolean result = mStatusBar.isPresenterFullyCollapsed()
                && (mQuickScrubController.onTouchEvent(event)
                && (mQuickScrubController.onTouchEvent(event)
                || ignoreProxyDownEvent
                || ignoreProxyDownEvent
@@ -168,11 +191,11 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
        if (mDockWindowEnabled) {
        if (mDockWindowEnabled) {
            result |= handleDockWindowEvent(event);
            result |= handleDockWindowEvent(event);
        }
        }
        return result;
        return result || mRecentsAnimationStarted;
    }
    }


    public void onDraw(Canvas canvas) {
    public void onDraw(Canvas canvas) {
        if (mOverviewEventSender.getProxy() != null) {
        if (mOverviewProxyService.getProxy() != null) {
            mQuickScrubController.onDraw(canvas);
            mQuickScrubController.onDraw(canvas);
        }
        }
    }
    }
+2 −19
Original line number Original line Diff line number Diff line
@@ -103,7 +103,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    private DeadZone mDeadZone;
    private DeadZone mDeadZone;
    private final NavigationBarTransitions mBarTransitions;
    private final NavigationBarTransitions mBarTransitions;
    private final OverviewProxyService mOverviewProxyService;
    private final OverviewProxyService mOverviewProxyService;
    private boolean mRecentsAnimationStarted;


    // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
    // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
    final static boolean WORKAROUND_INVALID_LAYOUT = true;
    final static boolean WORKAROUND_INVALID_LAYOUT = true;
@@ -263,7 +262,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
    }
    }


    public void setRecentsAnimationStarted(boolean started) {
    public void setRecentsAnimationStarted(boolean started) {
        mRecentsAnimationStarted = started;
        if (mRecentsOnboarding != null) {
        if (mRecentsOnboarding != null) {
            mRecentsOnboarding.onRecentsAnimationStarted();
            mRecentsOnboarding.onRecentsAnimationStarted();
        }
        }
@@ -277,22 +275,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav


    @Override
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
    public boolean onInterceptTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        return mGestureHelper.onInterceptTouchEvent(event);
        if (action == MotionEvent.ACTION_DOWN) {
            mRecentsAnimationStarted = false;
        } else if (action == MotionEvent.ACTION_UP) {
            // If the overview proxy service has not started the recents animation then clean up
            // after it to ensure that the nav bar buttons still work
            if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
                try {
                    ActivityManager.getService().cancelRecentsAnimation();
                } catch (RemoteException e) {
                    Log.e(TAG, "Could not cancel recents animation");
                }
            }
        }

        return mGestureHelper.onInterceptTouchEvent(event) || mRecentsAnimationStarted;
    }
    }


    @Override
    @Override
@@ -300,7 +283,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
        if (mGestureHelper.onTouchEvent(event)) {
        if (mGestureHelper.onTouchEvent(event)) {
            return true;
            return true;
        }
        }
        return mRecentsAnimationStarted || super.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
    }


    public void abortCurrentGesture() {
    public void abortCurrentGesture() {
+8 −1
Original line number Original line Diff line number Diff line
@@ -76,6 +76,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene


    private boolean mDraggingActive;
    private boolean mDraggingActive;
    private boolean mQuickScrubActive;
    private boolean mQuickScrubActive;
    private boolean mAllowQuickSwitch;
    private float mDownOffset;
    private float mDownOffset;
    private float mTranslation;
    private float mTranslation;
    private int mTouchDownX;
    private int mTouchDownX;
@@ -136,7 +137,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
        new GestureDetector.SimpleOnGestureListener() {
        new GestureDetector.SimpleOnGestureListener() {
            @Override
            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
                if (!isQuickScrubEnabled() || mQuickScrubActive ||
                if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
                        !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
                        !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
                    return false;
                    return false;
                }
                }
@@ -234,6 +235,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
                    homeButton.setDelayTouchFeedback(false);
                    homeButton.setDelayTouchFeedback(false);
                    mTouchDownX = mTouchDownY = -1;
                    mTouchDownX = mTouchDownY = -1;
                }
                }
                mAllowQuickSwitch = true;
                break;
                break;
            }
            }
            case MotionEvent.ACTION_MOVE: {
            case MotionEvent.ACTION_MOVE: {
@@ -418,6 +420,11 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
        mDraggingActive = false;
        mDraggingActive = false;
    }
    }


    public void cancelQuickSwitch() {
        mAllowQuickSwitch = false;
        mHandler.removeCallbacks(mLongPressRunnable);
    }

    private int getDimensionPixelSize(Context context, @DimenRes int resId) {
    private int getDimensionPixelSize(Context context, @DimenRes int resId) {
        return context.getResources().getDimensionPixelSize(resId);
        return context.getResources().getDimensionPixelSize(resId);
    }
    }