diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java index 6131acc91ca54..aa2fb32f13a89 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java @@ -16,6 +16,7 @@ package com.android.systemui.plugins.statusbar.phone; import android.graphics.Canvas; import android.view.MotionEvent; +import android.view.View; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.annotations.ProvidesInterface; @@ -42,6 +43,8 @@ public interface NavGesture extends Plugin { public void onLayout(boolean changed, int left, int top, int right, int bottom); + public void onNavigationButtonLongPress(View v); + public default void destroy() { } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index ef36610b48c60..8612445397252 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -80,4 +80,17 @@ oneway interface IOverviewProxy { * Sent when overview is to be hidden. */ void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); + + /** + * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined + * by passing the touch slop in the direction towards launcher from navigation bar. During and + * after this event is sent the caller will continue to send motion events. The motion + * {@param event} passed after the touch slop was exceeded will also be passed after by + * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be + * sent to cancel overview regardless the current state of launcher (eg. if overview is already + * visible, this event will still be sent if user swipes up). When this signal is sent, + * navigation bar will not handle any gestures such as quick scrub or switch and the home button + * will cancel (long) press. + */ + void onQuickStep(in MotionEvent event); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 846aaddf74de4..4799f398fb7a2 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -35,11 +35,6 @@ interface ISystemUiProxy { */ void startScreenPinning(int taskId) = 1; - /** - * Called when the overview service has started the recents animation. - */ - void onRecentsAnimationStarted() = 2; - /** * Specifies the text to be shown for onboarding the new swipe-up gesture to access recents. */ diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 041af0e471193..a4af6b26a8548 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -102,15 +102,6 @@ public class OverviewProxyService implements CallbackController= 0; --i) { - mConnectionCallbacks.get(i).onRecentsAnimationStarted(); + mConnectionCallbacks.get(i).onQuickStepStarted(); } } @@ -300,7 +291,7 @@ public class OverviewProxyService implements CallbackController { @@ -123,7 +127,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mNavigationBarView.getHomeButton().setClickable(true); mQuickScrubActive = false; mTranslation = 0; mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration()); @@ -165,7 +168,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } }; - public QuickScrubController(Context context) { + public QuickStepController(Context context) { mContext = context; mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mOverviewEventSender = Dependency.get(OverviewProxyService.class); @@ -197,31 +200,34 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { - final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); - if (!mNavigationBarView.isQuickScrubEnabled()) { - homeButton.setDelayTouchFeedback(false); + if (!mNavigationBarView.isQuickScrubEnabled() + && !mNavigationBarView.isQuickStepSwipeUpEnabled()) { + mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */); return false; } - + mNavigationBarView.requestUnbufferedDispatch(event); return handleTouchEvent(event); } /** - * @return true if we want to handle touch events for quick scrub/switch and prevent proxying - * the event to the overview service. + * @return true if we want to handle touch events for quick scrub/switch or if down event (that + * will get consumed and ignored). No events will be proxied to the overview service. */ @Override public boolean onTouchEvent(MotionEvent event) { - return handleTouchEvent(event); + // The same down event was just sent on intercept and therefore can be ignored here + final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN + && mOverviewEventSender.getProxy() != null; + return ignoreProxyDownEvent || handleTouchEvent(event); } private boolean handleTouchEvent(MotionEvent event) { - final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy(); final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); if (mGestureDetector.onTouchEvent(event)) { // If the fling has been handled on UP, then skip proxying the UP return true; } + final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME; int action = event.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { @@ -232,89 +238,99 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene mQuickScrubEndAnimator.end(); } mHomeButtonView = homeButton.getCurrentView(); - if (mNavigationBarView.isQuickScrubEnabled() - && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) { - mTouchDownX = x; - mTouchDownY = y; - homeButton.setDelayTouchFeedback(true); + homeButton.setDelayTouchFeedback(true /* delay */); + mTouchDownX = x; + mTouchDownY = y; + if (homePressed) { mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS); - } else { - homeButton.setDelayTouchFeedback(false); - mTouchDownX = mTouchDownY = -1; } + mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX); + mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX); + mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix); + mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix); + mQuickStepStarted = false; mAllowQuickSwitch = true; + mAllowGestureDetection = true; break; } case MotionEvent.ACTION_MOVE: { - if (mTouchDownX != -1) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int xDiff = Math.abs(x - mTouchDownX); - int yDiff = Math.abs(y - mTouchDownY); - boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff; - boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff; - boolean exceededTouchSlop, exceededPerpendicularTouchSlop; - int pos, touchDown, offset, trackSize; + if (mQuickStepStarted || !mAllowGestureDetection){ + break; + } + int x = (int) event.getX(); + int y = (int) event.getY(); + int xDiff = Math.abs(x - mTouchDownX); + int yDiff = Math.abs(y - mTouchDownY); + boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff; + boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff; + boolean exceededTouchSlop, exceededPerpendicularTouchSlop; + int pos, touchDown, offset, trackSize; - if (mIsVertical) { - exceededTouchSlop = exceededTouchSlopY; - exceededPerpendicularTouchSlop = exceededTouchSlopX; - pos = y; - touchDown = mTouchDownY; - offset = pos - mTrackRect.top; - trackSize = mTrackRect.height(); - } else { - exceededTouchSlop = exceededTouchSlopX; - exceededPerpendicularTouchSlop = exceededTouchSlopY; - pos = x; - touchDown = mTouchDownX; - offset = pos - mTrackRect.left; - trackSize = mTrackRect.width(); - } - // Do not start scrubbing when dragging in the perpendicular direction if we - // haven't already started quickscrub - if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) { - mHandler.removeCallbacksAndMessages(null); - return false; - } - if (!mDragPositive) { - offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width(); + if (mIsVertical) { + exceededTouchSlop = exceededTouchSlopY; + exceededPerpendicularTouchSlop = exceededTouchSlopX; + pos = y; + touchDown = mTouchDownY; + offset = pos - mTrackRect.top; + trackSize = mTrackRect.height(); + } else { + exceededTouchSlop = exceededTouchSlopX; + exceededPerpendicularTouchSlop = exceededTouchSlopY; + pos = x; + touchDown = mTouchDownX; + offset = pos - mTrackRect.left; + trackSize = mTrackRect.width(); + } + // Decide to start quickstep if dragging away from the navigation bar, otherwise in + // the parallel direction, decide to start quickscrub. Only one may run. + if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) { + if (mNavigationBarView.isQuickStepSwipeUpEnabled()) { + startQuickStep(event); } + break; + } - // Control the button movement - if (!mDraggingActive && exceededTouchSlop && !mRecentsAnimationStarted) { - boolean allowDrag = !mDragPositive - ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown; - if (allowDrag) { - mDownOffset = offset; - homeButton.setClickable(false); - mDraggingActive = true; - } + // Do not handle quick scrub/switch if disabled or hit target is not home button + if (!homePressed || !mNavigationBarView.isQuickScrubEnabled()) { + break; + } + + if (!mDragPositive) { + offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width(); + } + + // Control the button movement + if (!mDraggingActive && exceededTouchSlop) { + boolean allowDrag = !mDragPositive + ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown; + if (allowDrag) { + mDownOffset = offset; + homeButton.abortCurrentGesture(); + mDraggingActive = true; } - if (mDraggingActive && (mDragPositive && offset >= 0 - || !mDragPositive && offset <= 0)) { - float scrubFraction = - Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1); - mTranslation = !mDragPositive - ? Utilities.clamp(offset - mDownOffset, -trackSize, 0) - : Utilities.clamp(offset - mDownOffset, 0, trackSize); - if (mQuickScrubActive) { - try { - mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction); - if (DEBUG_OVERVIEW_PROXY) { - Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction); - } - } catch (RemoteException e) { - Log.e(TAG, "Failed to send progress of quick scrub.", e); + } + if (mDraggingActive && (mDragPositive && offset >= 0 + || !mDragPositive && offset <= 0)) { + float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1); + mTranslation = !mDragPositive + ? Utilities.clamp(offset - mDownOffset, -trackSize, 0) + : Utilities.clamp(offset - mDownOffset, 0, trackSize); + if (mQuickScrubActive) { + try { + mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction); } - } else { - mTranslation /= SWITCH_STICKINESS; - } - if (mIsVertical) { - mHomeButtonView.setTranslationY(mTranslation); - } else { - mHomeButtonView.setTranslationX(mTranslation); + } catch (RemoteException e) { + Log.e(TAG, "Failed to send progress of quick scrub.", e); } + } else { + mTranslation /= SWITCH_STICKINESS; + } + if (mIsVertical) { + mHomeButtonView.setTranslationY(mTranslation); + } else { + mHomeButtonView.setTranslationX(mTranslation); } } break; @@ -324,11 +340,20 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene endQuickScrub(true /* animate */); break; } - return mDraggingActive || mQuickScrubActive; + + // Proxy motion events to launcher if not handled by quick scrub/switch + boolean handled = mDraggingActive || mQuickScrubActive; + if (!handled && mAllowGestureDetection) { + proxyMotionEvents(event); + } + return handled || mQuickStepStarted; } @Override public void onDraw(Canvas canvas) { + if (mNavigationBarView.isQuickScrubEnabled()) { + return; + } int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor, mDarkTrackColor); mTrackPaint.setColor(color); @@ -381,6 +406,31 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } } + @Override + public void onNavigationButtonLongPress(View v) { + mAllowGestureDetection = false; + mHandler.removeCallbacksAndMessages(null); + } + + private void startQuickStep(MotionEvent event) { + mQuickStepStarted = true; + event.transform(mTransformGlobalMatrix); + try { + mOverviewEventSender.getProxy().onQuickStep(event); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Quick Step Start"); + } + } catch (RemoteException e) { + Log.e(TAG, "Failed to send quick step started.", e); + } finally { + event.transform(mTransformLocalMatrix); + } + mOverviewEventSender.notifyQuickStepStarted(); + mNavigationBarView.getHomeButton().abortCurrentGesture(); + cancelQuickSwitch(); + mHandler.removeCallbacksAndMessages(null); + } + private void startQuickScrub() { if (!mQuickScrubActive && mDraggingActive) { mQuickScrubActive = true; @@ -396,9 +446,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene } catch (RemoteException e) { Log.e(TAG, "Failed to send start of quick scrub.", e); } - } else { - // After long press do not allow quick scrub/switch - mTouchDownX = -1; } } @@ -421,11 +468,24 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene mDraggingActive = false; } - public void setRecentsAnimationStarted(boolean started) { - mRecentsAnimationStarted = started; - if (started) { - cancelQuickSwitch(); + private boolean proxyMotionEvents(MotionEvent event) { + final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy(); + event.transform(mTransformGlobalMatrix); + try { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget()); + } + overviewProxy.onMotionEvent(event); + if (DEBUG_OVERVIEW_PROXY) { + Log.d(TAG_OPS, "Send MotionEvent: " + event.toString()); + } + return true; + } catch (RemoteException e) { + Log.e(TAG, "Callback failed", e); + } finally { + event.transform(mTransformLocalMatrix); } + return false; } public void cancelQuickSwitch() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 3bcfd4b7f3811..e5fefd34ffb78 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -224,8 +224,10 @@ public class KeyButtonView extends ImageView implements ButtonInterface { case MotionEvent.ACTION_DOWN: mDownTime = SystemClock.uptimeMillis(); mLongClicked = false; - mTouchDownX = (int) ev.getX(); - mTouchDownY = (int) ev.getY(); + + // Use raw X and Y to detect gestures in case a parent changes the x and y values + mTouchDownX = (int) ev.getRawX(); + mTouchDownY = (int) ev.getRawY(); if (mCode != 0) { sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime); } else { @@ -241,8 +243,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface { postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout()); break; case MotionEvent.ACTION_MOVE: - x = (int)ev.getX(); - y = (int)ev.getY(); + x = (int)ev.getRawX(); + y = (int)ev.getRawY(); boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop; boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop; if (exceededTouchSlopX || exceededTouchSlopY) {